]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'ws/git-push-doc-grammofix' into maint-2.42
authorJunio C Hamano <gitster@pobox.com>
Thu, 2 Nov 2023 07:53:20 +0000 (16:53 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Nov 2023 07:53:20 +0000 (16:53 +0900)
Doc update.

* ws/git-push-doc-grammofix:
  git-push.txt: fix grammar

971 files changed:
.github/workflows/coverity.yml [new file with mode: 0644]
.github/workflows/main.yml
.gitignore
.mailmap
Documentation/.gitignore
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/MyFirstContribution.txt
Documentation/MyFirstObjectWalk.txt
Documentation/RelNotes/2.41.0.txt [new file with mode: 0644]
Documentation/RelNotes/2.42.0.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/asciidoc.conf
Documentation/blame-options.txt
Documentation/config.txt
Documentation/config/advice.txt
Documentation/config/difftool.txt
Documentation/config/feature.txt
Documentation/config/format.txt
Documentation/config/gc.txt
Documentation/config/http.txt
Documentation/config/mergetool.txt
Documentation/config/pack.txt
Documentation/config/rebase.txt
Documentation/config/sendemail.txt
Documentation/diff-options.txt
Documentation/doc-diff
Documentation/fetch-options.txt
Documentation/git-am.txt
Documentation/git-bisect.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-bundle.txt
Documentation/git-cat-file.txt
Documentation/git-checkout.txt
Documentation/git-clone.txt
Documentation/git-credential.txt
Documentation/git-cvsserver.txt
Documentation/git-describe.txt
Documentation/git-diff.txt
Documentation/git-difftool.txt
Documentation/git-fetch.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-gc.txt
Documentation/git-hash-object.txt
Documentation/git-interpret-trailers.txt
Documentation/git-ls-files.txt
Documentation/git-ls-remote.txt
Documentation/git-ls-tree.txt
Documentation/git-merge-tree.txt
Documentation/git-merge.txt
Documentation/git-mergetool.txt
Documentation/git-mktag.txt
Documentation/git-name-rev.txt
Documentation/git-notes.txt
Documentation/git-pack-redundant.txt
Documentation/git-pack-refs.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-rev-parse.txt
Documentation/git-send-email.txt
Documentation/git-show-branch.txt
Documentation/git-show-ref.txt
Documentation/git-sparse-checkout.txt
Documentation/git-stash.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/git-var.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcredentials.txt
Documentation/gitformat-pack.txt
Documentation/githooks.txt
Documentation/gitignore.txt
Documentation/gitmodules.txt
Documentation/gittutorial.txt
Documentation/gitweb.txt
Documentation/manpage-base-url.xsl.in [deleted file]
Documentation/manpage-normal.xsl
Documentation/manpage-quote-apos.xsl [deleted file]
Documentation/object-format-disclaimer.txt
Documentation/rev-list-options.txt
Documentation/revisions.txt
Documentation/scalar.txt
Documentation/technical/api-merge.txt
Documentation/technical/remembering-renames.txt
Documentation/urls-remotes.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
abspath.c
abspath.h [new file with mode: 0644]
add-interactive.c
add-patch.c
advice.c
advice.h
alias.c
alias.h
alloc.c
apply.c
apply.h
archive-tar.c
archive-zip.c
archive.c
archive.h
attr.c
attr.h
banned.h
base85.c
base85.h [new file with mode: 0644]
bisect.c
blame.c
blame.h
blob.c
bloom.c
branch.c
branch.h
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/credential.c
builtin/describe.c
builtin/diagnose.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-packed.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-ext.c
builtin/remote-fd.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
bundle.h
cache-tree.c
cache-tree.h
cache.h [deleted file]
cbtree.c
cbtree.h
chdir-notify.c
checkout.c
checkout.h
chunk-format.c
chunk-format.h
ci/lib.sh
ci/run-build-and-tests.sh
color.c
color.h
column.c
combine-diff.c
commit-graph.c
commit-graph.h
commit-reach.c
commit-reach.h
commit-slab-impl.h
commit.c
commit.h
common-main.c
compat/disk.h
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/linux/procinfo.c
compat/mingw.c
compat/mingw.h
compat/pread.c
compat/precompose_utf8.c
compat/sha1-chunked.c
compat/simple-ipc/ipc-shared.c
compat/simple-ipc/ipc-unix-socket.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
connect.h
connected.c
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/coccinelle/tests/unused.c [deleted file]
contrib/coccinelle/tests/unused.res [deleted file]
contrib/coccinelle/the_repository.cocci [new file with mode: 0644]
contrib/coccinelle/the_repository.pending.cocci [deleted file]
contrib/coccinelle/unused.cocci [deleted file]
contrib/completion/git-completion.bash
contrib/completion/git-prompt.sh
contrib/credential/gnome-keyring/.gitignore [deleted file]
contrib/credential/gnome-keyring/Makefile [deleted file]
contrib/credential/gnome-keyring/git-credential-gnome-keyring.c [deleted file]
contrib/credential/libsecret/.gitignore [new file with mode: 0644]
contrib/credential/libsecret/git-credential-libsecret.c
contrib/credential/osxkeychain/git-credential-osxkeychain.c
contrib/credential/wincred/git-credential-wincred.c
contrib/subtree/git-subtree.sh
contrib/subtree/t/Makefile
convert.c
convert.h
copy.c
copy.h [new file with mode: 0644]
credential.c
credential.h
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
date.h
decorate.c
delta-islands.c
detect-compiler
diagnose.c
diagnose.h
diff-lib.c
diff-merges.c
diff-no-index.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore-rotate.c
diffcore.h
dir-iterator.c
dir.c
dir.h
editor.c
editor.h [new file with mode: 0644]
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
gettext.c
git-compat-util.h
git-difftool--helper.sh
git-mergetool--lib.sh
git-mergetool.sh
git-send-email.perl
git-zlib.c [moved from zlib.c with 99% similarity]
git-zlib.h [new file with mode: 0644]
git.c
gitk-git/gitk
gpg-interface.c
gpg-interface.h
graph.c
grep.c
grep.h
hash-ll.h [new file with mode: 0644]
hash-lookup.c
hash.h
hashmap.c
hashmap.h
help.c
hex.c
hex.h [new file with mode: 0644]
hook.c
http-backend.c
http-fetch.c
http-push.c
http-walker.c
http.c
http.h
ident.c
ident.h [new file with mode: 0644]
imap-send.c
json-writer.c
khash.h
kwset.c
kwset.h
levenshtein.c
line-log.c
line-log.h
linear-assignment.c
list-objects-filter-options.c
list-objects-filter-options.h
list-objects-filter.c
list-objects.c
lockfile.c
log-tree.c
log-tree.h
ls-refs.c
mailinfo.c
mailmap.c
mailmap.h
match-trees.c
match-trees.h [new file with mode: 0644]
mem-pool.c
merge-blobs.c
merge-ll.c [moved from ll-merge.c with 91% similarity]
merge-ll.h [moved from ll-merge.h with 100% similarity]
merge-ort-wrappers.c
merge-ort.c
merge-ort.h
merge-recursive.c
merge.c
merge.h [new file with mode: 0644]
midx.c
name-hash.c
name-hash.h [new file with mode: 0644]
negotiator/default.c
negotiator/noop.c
negotiator/skipping.c
notes-cache.c
notes-merge.c
notes-utils.c
notes.c
notes.h
object-file.c
object-file.h [new file with mode: 0644]
object-name.c
object-name.h [new file with mode: 0644]
object-store-ll.h [new file with mode: 0644]
object-store.h
object.c
object.h
oid-array.c
oidmap.c
oidmap.h
oidset.c
oidtree.c
oidtree.h
oss-fuzz/fuzz-commit-graph.c
oss-fuzz/fuzz-pack-headers.c
oss-fuzz/fuzz-pack-idx.c
pack-bitmap-write.c
pack-bitmap.c
pack-bitmap.h
pack-check.c
pack-mtimes.c
pack-mtimes.h
pack-objects.c
pack-objects.h
pack-revindex.c
pack-revindex.h
pack-write.c
pack.h
packfile.c
packfile.h
pager.c
pager.h [new file with mode: 0644]
parallel-checkout.c
parse-options-cb.c
parse-options.c
parse-options.h
patch-ids.c
path.c
path.h
pathspec.c
pathspec.h
pkt-line.c
pkt-line.h
po/TEAMS
po/bg.po
po/ca.po
po/de.po
po/fr.po
po/id.po
po/ru.po
po/sv.po
po/tr.po
po/uk.po [new file with mode: 0644]
po/zh_CN.po
po/zh_TW.po
preload-index.c
preload-index.h [new file with mode: 0644]
pretty.c
pretty.h
prio-queue.c
progress.c
promisor-remote.c
promisor-remote.h
prompt.c
protocol-caps.c
protocol.c
protocol.h
prune-packed.c
quote.c
quote.h
range-diff.c
reachable.c
read-cache-ll.h [new file with mode: 0644]
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-walk.h
reflog.c
refs.c
refs.h
refs/debug.c
refs/files-backend.c
refs/iterator.c
refs/packed-backend.c
refs/ref-cache.c
refs/ref-cache.h
refs/refs-internal.h
refspec.c
reftable/dump.c
reftable/error.c
reftable/publicbasics.c
reftable/system.h
reftable/tree.c
reftable/tree_test.c
remote-curl.c
remote.c
remote.h
replace-object.c
replace-object.h
repo-settings.c
repository.c
repository.h
rerere.c
rerere.h
reset.c
reset.h
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
sequencer.h
serve.c
server-info.c
server-info.h [new file with mode: 0644]
setup.c
setup.h [new file with mode: 0644]
sha1/openssl.h [new file with mode: 0644]
sha1dc_git.c
sha256/gcrypt.h
sha256/openssl.h [new file with mode: 0644]
shallow.c
shallow.h
shell.c
sideband.c
sigchain.c
sparse-index.c
sparse-index.h
split-index.c
split-index.h
statinfo.c [new file with mode: 0644]
statinfo.h [new file with mode: 0644]
strbuf.c
strbuf.h
streaming.c
streaming.h
string-list.c
string-list.h
strvec.c
sub-process.c
sub-process.h
submodule-config.c
submodule-config.h
submodule.c
symlinks.c
symlinks.h [new file with mode: 0644]
t/.gitattributes
t/Makefile
t/README
t/aggregate-results.sh
t/annotate-tests.sh
t/chainlint.pl
t/chainlint/unclosed-here-doc-indent.expect [new file with mode: 0644]
t/chainlint/unclosed-here-doc-indent.test [new file with mode: 0644]
t/chainlint/unclosed-here-doc.expect [new file with mode: 0644]
t/chainlint/unclosed-here-doc.test [new file with mode: 0644]
t/helper/test-advise.c
t/helper/test-bitmap.c
t/helper/test-bloom.c
t/helper/test-bundle-uri.c
t/helper/test-cache-tree.c
t/helper/test-chmtime.c
t/helper/test-config.c
t/helper/test-crontab.c
t/helper/test-ctype.c
t/helper/test-date.c
t/helper/test-delta.c
t/helper/test-drop-caches.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-example-decorate.c
t/helper/test-fast-rebase.c
t/helper/test-fsmonitor-client.c
t/helper/test-hash-speed.c
t/helper/test-hash.c
t/helper/test-hashmap.c
t/helper/test-hexdump.c
t/helper/test-index-version.c
t/helper/test-json-writer.c
t/helper/test-lazy-init-name-hash.c
t/helper/test-match-trees.c
t/helper/test-mergesort.c
t/helper/test-oid-array.c
t/helper/test-oidmap.c
t/helper/test-oidtree.c
t/helper/test-online-cpus.c
t/helper/test-pack-mtimes.c
t/helper/test-parse-options.c
t/helper/test-parse-pathspec-file.c
t/helper/test-partial-clone.c
t/helper/test-path-utils.c
t/helper/test-pcre2-config.c
t/helper/test-pkt-line.c
t/helper/test-prio-queue.c
t/helper/test-proc-receive.c
t/helper/test-progress.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-reftable.c
t/helper/test-repository.c
t/helper/test-revision-walking.c
t/helper/test-run-command.c
t/helper/test-scrap-cache-tree.c
t/helper/test-serve-v2.c
t/helper/test-sha1.c
t/helper/test-sha256.c
t/helper/test-sigchain.c
t/helper/test-simple-ipc.c
t/helper/test-strcmp-offset.c
t/helper/test-string-list.c
t/helper/test-submodule-config.c
t/helper/test-submodule-nested-repo-config.c
t/helper/test-submodule.c
t/helper/test-subprocess.c
t/helper/test-trace2.c
t/helper/test-userdiff.c
t/helper/test-wildmatch.c
t/helper/test-write-cache.c
t/helper/test-xml-encode.c
t/lib-commit-graph.sh
t/lib-credential.sh
t/lib-diff-alternative.sh
t/lib-gpg.sh
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/lib-httpd/apply-one-time-perl.sh
t/lib-httpd/nph-custom-auth.sh [new file with mode: 0644]
t/lib-patch-mode.sh
t/lib-submodule-update.sh
t/perf/p1500-graph-walks.sh [new file with mode: 0755]
t/perf/p2000-sparse-operations.sh
t/perf/p5312-pack-bitmaps-revs.sh
t/t0000-basic.sh
t/t0001-init.sh
t/t0002-gitfile.sh
t/t0003-attributes.sh
t/t0007-git-var.sh
t/t0020-crlf.sh
t/t0027-auto-crlf.sh
t/t0030-stripspace.sh
t/t0035-safe-bare-repository.sh
t/t0040-parse-options.sh
t/t0041-usage.sh
t/t0055-beyond-symlinks.sh
t/t0060-path-utils.sh
t/t0063-string-list.sh
t/t0068-for-each-repo.sh
t/t0091-bugreport.sh
t/t0100-previous.sh
t/t0211-trace2-perf.sh
t/t0300-credentials.sh
t/t0301-credential-cache.sh
t/t1001-read-tree-m-2way.sh
t/t1002-read-tree-m-u-2way.sh
t/t1005-read-tree-reset.sh
t/t1006-cat-file.sh
t/t1010-mktree.sh
t/t1091-sparse-checkout-builtin.sh
t/t1092-sparse-checkout-compatibility.sh
t/t1300-config.sh
t/t1301-shared-repo.sh
t/t1302-repo-version.sh
t/t1308-config-set.sh
t/t1400-update-ref.sh
t/t1401-symbolic-ref.sh
t/t1404-update-ref-errors.sh
t/t1419-exclude-refs.sh [new file with mode: 0755]
t/t1450-fsck.sh
t/t1502-rev-parse-parseopt.sh
t/t1504-ceiling-dirs.sh
t/t1507-rev-parse-upstream.sh
t/t1508-at-combinations.sh
t/t1514-rev-parse-push.sh
t/t1800-hook.sh
t/t2005-checkout-index-symlinks.sh
t/t2019-checkout-ambiguous-ref.sh
t/t2021-checkout-overwrite.sh
t/t2024-checkout-dwim.sh
t/t2027-checkout-track.sh
t/t2060-switch.sh
t/t2070-restore.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/t3060-ls-files-with-tree.sh
t/t3070-wildmatch.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/t3210-pack-refs.sh
t/t3301-notes.sh
t/t3309-notes-merge-auto-resolve.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/t3422-rebase-incompatible-options.sh
t/t3427-rebase-subtree.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/t4018-diff-funcname.sh
t/t4022-diff-rewrite.sh
t/t4034-diff-words.sh
t/t4040-whitespace-status.sh
t/t4047-diff-dirstat.sh
t/t4053-diff-no-index.sh
t/t4062-diff-pickaxe.sh
t/t4067-diff-partial-clone.sh
t/t4115-apply-symlink.sh
t/t4141-apply-too-large.sh
t/t4150-am.sh
t/t4202-log.sh
t/t4203-mailmap.sh
t/t4205-log-pretty-formats.sh
t/t4206-log-follow-harder-copies.sh
t/t4212-log-corrupt.sh
t/t4258/mbox
t/t4300-merge-tree.sh
t/t5000-tar-tree.sh
t/t5001-archive-attr.sh
t/t5100/msg0002
t/t5100/msg0003
t/t5100/msg0012--message-id
t/t5100/quoted-cr.mbox
t/t5100/sample.mbox
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/t5318-commit-graph.sh
t/t5319-multi-pack-index.sh
t/t5324-split-commit-graph.sh
t/t5325-reverse-index.sh
t/t5326-multi-pack-bitmaps.sh
t/t5328-commit-graph-64bit-time.sh
t/t5329-pack-objects-cruft.sh
t/t5331-pack-objects-stdin.sh [new file with mode: 0755]
t/t5351-unpack-large-objects.sh
t/t5404-tracking-branches.sh
t/t5407-post-rewrite-hook.sh
t/t5510-fetch.sh
t/t5512-ls-remote.sh
t/t5514-fetch-multiple.sh
t/t5516-fetch-push.sh
t/t5517-push-mirror.sh
t/t5522-pull-symlink.sh
t/t5523-push-upstream.sh
t/t5525-fetch-tagopt.sh
t/t5526-fetch-submodules.sh
t/t5543-atomic-push.sh
t/t5546-receive-limits.sh
t/t5551-http-fetch-smart.sh
t/t5552-skipping-fetch-negotiator.sh
t/t5558-clone-bundle-uri.sh
t/t5563-simple-http-auth.sh [new file with mode: 0755]
t/t5571-pre-push-hook.sh
t/t5572-pull-submodule.sh
t/t5574-fetch-output.sh [new file with mode: 0755]
t/t5583-push-branches.sh [new file with mode: 0755]
t/t5604-clone-reference.sh
t/t5605-clone-local.sh
t/t5606-clone-options.sh
t/t5616-partial-clone.sh
t/t5700-protocol-v1.sh
t/t5702-protocol-v2.sh
t/t6006-rev-list-format.sh
t/t6017-rev-list-stdin.sh
t/t6018-rev-list-glob.sh
t/t6020-bundle-misc.sh
t/t6021-rev-list-exclude-hidden.sh
t/t6030-bisect-porcelain.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/t6301-for-each-ref-errors.sh
t/t6302-for-each-ref-filter.sh
t/t6406-merge-attr.sh
t/t6500-gc.sh
t/t6501-freshen-objects.sh
t/t6600-test-reach.sh
t/t7001-mv.sh
t/t7004-tag.sh
t/t7031-verify-tag-signed-ssh.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/t7300-clean.sh
t/t7400-submodule-basic.sh
t/t7402-submodule-rebase.sh
t/t7406-submodule-update.sh
t/t7413-submodule-is-active.sh
t/t7502-commit-porcelain.sh
t/t7504-commit-msg-hook.sh
t/t7508-status.sh
t/t7510-signed-commit.sh
t/t7512-status-help.sh
t/t7516-commit-races.sh
t/t7518-ident-corner-cases.sh
t/t7527-builtin-fsmonitor.sh
t/t7600-merge.sh
t/t7610-mergetool.sh
t/t7700-repack.sh
t/t7701-repack-unpack-unreachable.sh
t/t7703-repack-geometric.sh
t/t7800-difftool.sh
t/t7810-grep.sh
t/t7814-grep-recurse-submodules.sh
t/t7900-maintenance.sh
t/t9001-send-email.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/t9300-fast-import.sh
t/t9304-fast-import-marks.sh
t/t9351-fast-export-anonymize.sh
t/t9400-git-cvsserver-server.sh
t/t9800-git-p4-basic.sh
t/t9902-completion.sh
t/t9903-bash-prompt.sh
t/test-lib-functions.sh
t/test-lib.sh
tag.c
tempfile.c
templates/hooks--sendemail-validate.sample [new file with mode: 0755]
thread-utils.c
tmp-objdir.c
trace.c
trace.h
trace2.c
trace2.h
trace2/tr2_cfg.c
trace2/tr2_cmd_name.c
trace2/tr2_ctr.c
trace2/tr2_dst.c
trace2/tr2_sid.c
trace2/tr2_sysenv.c
trace2/tr2_tbuf.c
trace2/tr2_tgt.h
trace2/tr2_tgt_event.c
trace2/tr2_tgt_normal.c
trace2/tr2_tgt_perf.c
trace2/tr2_tls.c
trace2/tr2_tmr.c
trailer.c
transport-helper.c
transport.c
transport.h
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unicode-width.h
unix-socket.c
unix-stream-server.c
unpack-trees.c
unpack-trees.h
upload-pack.c
url.c
urlmatch.c
urlmatch.h
usage.c
userdiff.c
userdiff.h
versioncmp.c
versioncmp.h [new file with mode: 0644]
walker.c
wildmatch.c
wildmatch.h
worktree.c
worktree.h
wrapper.c
wrapper.h [new file with mode: 0644]
write-or-die.c
write-or-die.h [new file with mode: 0644]
ws.c
ws.h [new file with mode: 0644]
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..1b41278a7f0d57a87f3621b6cb56bf0f5198876a 100644 (file)
@@ -5,6 +5,19 @@ 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
@@ -246,9 +259,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 +283,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 95aaa1c83318e2f6174def3e9059b4029a1e31f8..dc31d70b8c1e98b14a4e76d5fa0e35cfd0bccc34 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -65,6 +65,7 @@ Derrick Stolee <derrickstolee@github.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>
+Emily Shaffer <nasamuffin@google.com> <emilyshaffer@google.com>
 Eric Blake <eblake@redhat.com> <ebb9@byu.net>
 Eric Hanchrow <eric.hanchrow@gmail.com> <offby1@blarg.net>
 Eric S. Raymond <esr@thyrsus.com>
@@ -79,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 1c3771e7d72f690d07f4a4ce49275a3a74709dfd..a48448de32f98b1a054b36e886ea920bccebc494 100644 (file)
@@ -10,7 +10,6 @@ howto-index.txt
 doc.dep
 cmds-*.txt
 mergetools-*.txt
-manpage-base-url.xsl
 SubmittingPatches.txt
 tmp-doc-diff/
 GIT-ASCIIDOCFLAGS
index 9d5c27807a40bcf597c6266b848d89f15afb5165..65af8d82cedd5fdfd46005d4b4e75114a74810fb 100644 (file)
@@ -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:
 
@@ -442,8 +446,12 @@ For C programs:
    detail.
 
  - The first #include in C files, except in platform specific compat/
-   implementations, must be either "git-compat-util.h", "cache.h" or
-   "builtin.h".  You do not have to include more than one of these.
+   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 "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.
 
  - A C file must directly include the header files that declare the
    functions and the types it uses, except for the functions and types
@@ -683,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 9c67c3a1c50d4b87853a1cb2fcbfd6f0619d118c..b629176d7d2d6776e0a66fbda466915219f32bc2 100644 (file)
@@ -144,14 +144,16 @@ man5dir = $(mandir)/man5
 man7dir = $(mandir)/man7
 # DESTDIR =
 
+GIT_DATE := $(shell git show --quiet --pretty='%as')
+
 ASCIIDOC = asciidoc
 ASCIIDOC_EXTRA =
 ASCIIDOC_HTML = xhtml11
 ASCIIDOC_DOCBOOK = docbook
 ASCIIDOC_CONF = -f asciidoc.conf
 ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) \
-               -amanversion=$(GIT_VERSION) \
-               -amanmanual='Git Manual' -amansource='Git'
+               -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)' \
+               -arevdate='$(GIT_DATE)'
 ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS
 TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
 TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK)
@@ -189,15 +191,7 @@ endif
 ifndef MAN_BASE_URL
 MAN_BASE_URL = file://$(htmldir)/
 endif
-XMLTO_EXTRA += -m manpage-base-url.xsl
-
-# If your target system uses GNU groff, it may try to render
-# apostrophes as a "pretty" apostrophe using unicode.  This breaks
-# cut&paste, so you should set GNU_ROFF to force them to be ASCII
-# apostrophes.  Unfortunately does not work with non-GNU roff.
-ifdef GNU_ROFF
-XMLTO_EXTRA += -m manpage-quote-apos.xsl
-endif
+XMLTO_EXTRA += --stringparam man.base.url.for.relative.links='$(MAN_BASE_URL)'
 
 ifdef USE_ASCIIDOCTOR
 ASCIIDOC = asciidoctor
@@ -339,7 +333,6 @@ clean:
        $(RM) technical/*.html technical/api-index.txt
        $(RM) SubmittingPatches.txt
        $(RM) $(cmds_txt) $(mergetools_txt) *.made
-       $(RM) manpage-base-url.xsl
        $(RM) GIT-ASCIIDOCFLAGS
 
 $(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS)
@@ -348,11 +341,7 @@ $(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS)
 $(OBSOLETE_HTML): %.html : %.txto $(ASCIIDOC_DEPS)
        $(QUIET_ASCIIDOC)$(TXT_TO_HTML) -o $@ $<
 
-manpage-base-url.xsl: manpage-base-url.xsl.in
-       $(QUIET_GEN)sed "s|@@MAN_BASE_URL@@|$(MAN_BASE_URL)|" $< > $@
-
-
-manpage-prereqs := manpage-base-url.xsl $(wildcard manpage*.xsl)
+manpage-prereqs := $(wildcard manpage*.xsl)
 manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
 
 %.1 : %.xml $(manpage-prereqs)
index ccfd0cb5f3e2aadb04bed17b5082ae71fc5fa2e0..62d11a5cd7f909e2e038e1f768bafddc82be210d 100644 (file)
@@ -1164,28 +1164,28 @@ After you run this command, `format-patch` will output the patches to the `psuh/
 directory, alongside the v1 patches. Using a single directory makes it easy to
 refer to the old v1 patches while proofreading the v2 patches, but you will need
 to be careful to send out only the v2 patches. We will use a pattern like
-"psuh/v2-*.patch" (not "psuh/*.patch", which would match v1 and v2 patches).
+`psuh/v2-*.patch` (not `psuh/*.patch`, which would match v1 and v2 patches).
 
 Edit your cover letter again. Now is a good time to mention what's different
 between your last version and now, if it's something significant. You do not
 need the exact same body in your second cover letter; focus on explaining to
 reviewers the changes you've made that may not be as visible.
 
-You will also need to go and find the Message-Id of your previous cover letter.
+You will also need to go and find the Message-ID of your previous cover letter.
 You can either note it when you send the first series, from the output of `git
 send-email`, or you can look it up on the
 https://lore.kernel.org/git[mailing list]. Find your cover letter in the
-archives, click on it, then click "permalink" or "raw" to reveal the Message-Id
+archives, click on it, then click "permalink" or "raw" to reveal the Message-ID
 header. It should match:
 
 ----
-Message-Id: <foo.12345.author@example.com>
+Message-ID: <foo.12345.author@example.com>
 ----
 
-Your Message-Id is `<foo.12345.author@example.com>`. This example will be used
-below as well; make sure to replace it with the correct Message-Id for your
-**previous cover letter** - that is, if you're sending v2, use the Message-Id
-from v1; if you're sending v3, use the Message-Id from v2.
+Your Message-ID is `<foo.12345.author@example.com>`. This example will be used
+below as well; make sure to replace it with the correct Message-ID for your
+**previous cover letter** - that is, if you're sending v2, use the Message-ID
+from v1; if you're sending v3, use the Message-ID from v2.
 
 While you're looking at the email, you should also note who is CC'd, as it's
 common practice in the mailing list to keep all CCs on a thread. You can add
@@ -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.41.0.txt b/Documentation/RelNotes/2.41.0.txt
new file mode 100644 (file)
index 0000000..8a9e170
--- /dev/null
@@ -0,0 +1,399 @@
+Git v2.41 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * Allow information carried on the WWW-Authenticate header to be
+   passed to the credential helpers.
+
+ * A new "fetch.hideRefs" option can be used to exclude specified refs
+   from "rev-list --objects --stdin --not --all" traversal for
+   checking object connectivity, most useful when there are many
+   unrelated histories in a single repository.
+
+ * "git push" has been taught to allow deletion of refs with one-level
+   names to help repairing a repository who acquired such a ref by
+   mistake.  In general, we don't encourage use of such a ref, and
+   creation or update to such a ref is rejected as before.
+
+ * Allow "git bisect reset" to check out the original branch when the
+   branch is already checked out in a different worktree linked to the
+   same repository.
+
+ * A few subcommands have been taught to stop users from working on a
+   branch that is being used in another worktree linked to the same
+   repository.
+
+ * "git format-patch" learned to write a log-message only output file
+   for empty commits.
+
+ * "git format-patch" honors the src/dst prefixes set to nonstandard
+   values with configuration variables like "diff.noprefix", causing
+   receiving end of the patch that expects the standard -p1 format to
+   break.  "format-patch" has been taught to ignore end-user configuration
+   and always use the standard prefixes.
+
+   This is a backward compatibility breaking change.
+
+ * Lift the limitation that colored prompts can only be used with
+   PROMPT_COMMAND mode.
+
+ * "git blame --contents=<file> <rev> -- <path>" used to be forbidden,
+   but now it finds the origins of lines starting at <file> contents
+   through the history that leads to <rev>.
+
+ * "git pack-redundant" gave a warning when run, as the command has
+   outlived its usefulness long ago and is nominated for future
+   removal.  Now we escalate to give an error.
+
+ * "git clone" from an empty repository learned to propagate the
+   choice of the hash algorithm from the source repository to the
+   newly created repository over any one of the v0/v1/v2 protocol.
+
+ * "git mergetool" and "git difftool" learns a new configuration
+   guiDefault to optionally favor configured guitool over non-gui-tool
+   automatically when $DISPLAY is set.
+
+ * "git branch -d origin/master" would say "no such branch", but it is
+   likely a missed "-r" if refs/remotes/origin/master exists.  The
+   command has been taught to give such a hint in its error message.
+
+ * Clean-up of the code path that deals with merge strategy option
+   handling in "git rebase".
+
+ * "git clone --local" stops copying from an original repository that
+   has symbolic links inside its $GIT_DIR; an error message when that
+   happens has been updated.
+
+ * The "--format=..." option of "git for-each-ref", "git branch", and
+   "git tag" commands learn "--omit-empty" to hide refs whose
+   formatting results in an empty string from the output.
+
+ * The sendemail-validate validate hook learned to pass the total
+   number of input files and where in the sequence each invocation is
+   via environment variables.
+
+ * When "gc" needs to retain unreachable objects, packing them into
+   cruft packs (instead of exploding them into loose object files) has
+   been offered as a more efficient option for some time.  Now the use
+   of cruft packs has been made the default and no longer considered
+   an experimental feature.
+
+ * The output given by "git blame" that attributes a line to contents
+   taken from the file specified by the "--contents" option shows it
+   differently from a line attributed to the working tree file.
+
+ * "git send-email" learned to give the e-mail headers to the validate
+   hook by passing an extra argument from the command line.
+
+ * The credential subsystem learns to help OAuth framework.
+
+ * The titles of manual pages used to be chomped at an unreasonably
+   short limit, which has been removed.
+
+ * Error messages given when working on an unborn branch that is
+   checked out in another worktree have been improved.
+
+ * The documentation was misleading about the interaction between
+   GIT_DEFAULT_HASH and "git clone", which has been clarified to
+   stress that the variable is to be ignored by the command.
+
+ * "git send-email" learned "--header-cmd=<cmd>" that can inject
+   arbitrary e-mail header lines to the outgoing messages.
+
+ * "git fsck" learned to detect bit-flip breakages in the reachability
+   bitmap files.
+
+ * The "--stdin" option of "git name-rev" has been replaced with
+   the "--annotate-stdin" option more than a year ago.  We stop
+   advertising it in the "git name-rev -h" output.
+
+ * "git push --all" gained an alias "git push --branches".
+
+ * "git fetch" learned the "--porcelain" option that emits what it did
+   in a machine-parseable format.
+
+ * "git --attr-source=<tree> cmd $args" is a new way to have any
+   command to read attributes not from the working tree but from the
+   given tree object.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code clean-up to clarify directory traversal API.
+
+ * Code clean-up to clarify the rule that "git-compat-util.h" must be
+   the first to be included.
+
+ * More work towards -Wunused.
+
+ * Instead of forcing each command to choose to honor GPG related
+   configuration variables, make the subsystem lazily initialize
+   itself.
+
+ * Remove workaround for ancient versions of DocBook to make it work
+   correctly with groff, which has not been necessary since docbook
+   1.76 from 2010.
+
+ * Code clean-up to include and/or uninclude parse-options.h file as
+   needed.
+
+ * The code path that reports what "git fetch" did to each ref has
+   been cleaned up.
+
+ * Assorted config API updates.
+
+ * A few configuration variables to tell the cURL library that
+   different types of ssl-cert and ssl-key are in use have been added.
+
+ * Split key function and data structure definitions out of cache.h to
+   new header files and adjust the users.
+
+ * "git fetch --all" does not have to download and handle the same
+   bundleURI over and over, which has been corrected.
+
+ * "git sparse-checkout" command learns a debugging aid for the sparse
+   rule definitions.
+
+ * "git write-tree" learns to work better with sparse-index.
+
+ * The on-disk reverse index that allows mapping from the pack offset
+   to the object name for the object stored at the offset has been
+   enabled by default.
+
+ * "git fsck" learned to validate the on-disk pack reverse index files.
+
+ * strtok() and strtok_r() are banned in this codebase.
+
+ * The detect-compilers script to help auto-tweaking the build system
+   had trouble working with compilers whose version number has extra
+   suffixes.  The script has been taught that certain suffixes (like
+   "-win32" in "gcc 10-win32") can be safely stripped as they share
+   the same features and bugs with the version without the suffix.
+
+ * ctype tests have been taught to test EOF, too.
+
+ * The implementation of credential helpers used fgets() over fixed
+   size buffers to read protocol messages, causing the remainder of
+   the folded long line to trigger unexpected behaviour, which has
+   been corrected.
+
+ * The implementation of the default "negotiator", used to find common
+   ancestor over the network for object tranfer, used to be recursive;
+   it was updated to be iterative to conserve stackspace usage.
+
+ * Our custom callout formatter is no longer used in the documentation
+   formatting toolchain, as the upstream default ones give better
+   output these days.
+
+ * The tracing mechanism learned to notice and report when
+   auto-discovered bare repositories are being used, as allowing so
+   without explicitly stating the user intends to do so (with setting
+   GIT_DIR for example) can be used with social engineering as an
+   attack vector.
+
+ * "git diff-files" learned not to expand sparse-index unless needed.
+
+
+Fixes since v2.40
+-----------------
+
+ * "git fsck" learned to check the index files in other worktrees,
+   just like "git gc" honors them as anchoring points.
+   (merge 8d3e7eac52 jk/fsck-indices-in-worktrees later to maint).
+
+ * Fix a segfaulting loop.  The function and its caller may need
+   further clean-up.
+   (merge c5773dc078 ew/commit-reach-clean-up-flags-fix later to maint).
+
+ * "git restore" supports options like "--ours" that are only
+   meaningful during a conflicted merge, but these options are only
+   meaningful when updating the working tree files.  These options are
+   marked to be incompatible when both "--staged" and "--worktree" are
+   in effect.
+   (merge ee8a88826a ak/restore-both-incompatible-with-conflicts later to maint).
+
+ * Simplify UI to control progress meter given by "git bundle" command.
+   (merge 8b95521edb jk/bundle-progress later to maint).
+
+ * "git bundle" learned that "-" is a common way to say that the input
+   comes from the standard input and/or the output goes to the
+   standard output.  It used to work only for output and only from the
+   root level of the working tree.
+   (merge 0bbe10313e jk/bundle-use-dash-for-stdfiles later to maint).
+
+ * Once we start running, we assumed that the list of alternate object
+   databases would never change.  Hook into the machinery used to
+   update the list of packfiles during runtime to update this list as
+   well.
+   (merge e2d003dbed ds/reprepare-alternates-when-repreparing-packfiles later to maint).
+
+ * The code to parse "git rebase -X<opt>" was not prepared to see an
+   unparsable option string, which has been corrected.
+   (merge 15a4cc912e ab/fix-strategy-opts-parsing later to maint).
+
+ * "git add -p" while the index is unmerged sometimes failed to parse
+   the diff output it internally produces and died, which has been
+   corrected.
+   (merge 28d1122f9c jk/add-p-unmerged-fix later to maint).
+
+ * Fix for a "ls-files --format="%(path)" that produced nonsense
+   output, which was a bug in 2.38.
+   (merge cfb62dd006 aj/ls-files-format-fix later to maint).
+
+ * "git receive-pack" that responds to "git push" requests failed to
+   clean a stale lockfile when killed in the middle, which has been
+   corrected.
+   (merge c55c30669c ps/receive-pack-unlock-before-die later to maint).
+
+ * "git rev-parse --quiet foo@{u}", or anything that asks @{u} to be
+   parsed with GET_OID_QUIETLY option, did not quietly fail, which has
+   been corrected.
+   (merge dfbfdc521d fc/oid-quietly-parse-upstream later to maint).
+
+ * Transports that do not support protocol v2 did not correctly fall
+   back to protocol v0 under certain conditions, which has been
+   corrected.
+   (merge eaa0fd6584 jk/fix-proto-downgrade-to-v0 later to maint).
+
+ * time(2) on glib 2.31+, especially on Linux, goes out of sync with
+   higher resolution timers used for gettimeofday(2) and by the
+   filesystem.  Replace all calls to it with a git_time() wrapper and
+   (merge 370ddcbc89 pe/time-use-gettimeofday later to maint).
+
+ * Code clean-up to use designated initializers in parse-options API.
+   (merge 353e6d4554 sg/parse-options-h-initializers later to maint).
+
+ * A recent-ish change to allow unicode character classes to be used
+   with "grep -P" triggered a JIT bug in older pcre2 libraries.
+   The problematic change in Git built with these older libraries has
+   been disabled to work around the bug.
+   (merge 14b9a04479 mk/workaround-pcre-jit-ucp-bug later to maint).
+
+ * The wildmatch library code unlearns exponential behaviour it
+   acquired some time ago since it was borrowed from rsync.
+   (merge 3dc0b7f0dc pw/wildmatch-fixes later to maint).
+
+ * The index files can become corrupt under certain conditions when
+   the split-index feature is in use, especially together with
+   fsmonitor, which have been corrected.
+   (merge 061dd722dc js/split-index-fixes later to maint).
+
+ * Document what the pathname-looking strings in "rev-list --object"
+   output are for and what they mean.
+   (merge 15364d2a3c jk/document-rev-list-object-name later to maint).
+
+ * Fix unnecessary truncation of generation numbers used in-core.
+   (merge d3af1c193d ps/ahead-behind-truncation-fix later to maint).
+
+ * Code clean-up around the use of the_repository.
+   (merge 4a93b899c1 ab/remove-implicit-use-of-the-repository later to maint).
+
+ * Consistently spell "Message-ID" as such, not "Message-Id".
+   (merge ba4324c4e1 jc/spell-id-in-both-caps-in-message-id later to maint).
+
+ * Correct use of an uninitialized structure member.
+   (merge dc12ee77ab jx/cap-object-info-uninitialized-fix later to maint).
+
+ * Tests had a few places where we ignored PERL_PATH and blindly used
+   /usr/bin/perl, which have been corrected.
+   (merge c1917156a0 jk/use-perl-path-consistently later to maint).
+
+ * Documentation mark-up fix.
+   (merge 78b6369e67 la/mfc-markup-fix later to maint).
+
+ * Doc toolchain update to remove old workaround for AsciiDoc.
+   (merge 8806120de6 fc/remove-header-workarounds-for-asciidoc later to maint).
+
+ * The userdiff regexp patterns for various filetypes that are built
+   into the system have been updated to avoid triggering regexp errors
+   from UTF-8 aware regex engines.
+   (merge be39144954 rs/userdiff-multibyte-regex later to maint).
+
+ * The approxidate() API has been simplified by losing an extra
+   function that did the same thing as another one.
+   (merge 8a7f0b666f rs/remove-approxidate-relative later to maint).
+
+ * Code clean-up to replace a hardcoded constant with a CPP macro.
+   (merge c870de6502 rs/get-tar-commit-id-use-defined-const later to maint).
+
+ * Doc build simplification.
+   (merge 9a09ed3229 fc/doc-stop-using-manversion later to maint).
+
+ * "git archive" run from a subdirectory mishandled attributes and
+   paths outside the current directory.
+   (merge 92b1dd1b9e rs/archive-from-subdirectory-fixes later to maint).
+
+ * The code to parse capability list for v0 on-wire protocol fell into
+   an infinite loop when a capability appears multiple times, which
+   has been corrected.
+
+ * Geometric repacking ("git repack --geometric=<n>") in a repository
+   that borrows from an alternate object database had various corner
+   case bugs, which have been corrected.
+   (merge d85cd18777 ps/fix-geom-repack-with-alternates later to maint).
+
+ * The "%GT" placeholder for the "--format" option of "git log" and
+   friends caused BUG() to trigger on a commit signed with an unknown
+   key, which has been corrected.
+   (merge 7891e46585 jk/gpg-trust-level-fix later to maint).
+
+ * The completion script used to use bare "read" without the "-r"
+   option to read the contents of various state files, which risked
+   getting confused with backslashes in them.  This has been
+   corrected.
+   (merge 197152098a ek/completion-use-read-r-to-read-literally later to maint).
+
+ * A small API fix to the ort merge strategy backend.
+   (merge 000c4ceca7 en/ort-finalize-after-0-merges-fix later to maint).
+
+ * The commit object parser has been taught to be a bit more lenient
+   to parse timestamps on the author/committer line with a malformed
+   author/committer ident.
+   (merge 90ef0f14eb jk/parse-commit-with-malformed-ident later to maint).
+
+ * Retitle a test script with an overly narrow name.
+   (merge 8bb19c14fb ob/t3501-retitle later to maint).
+
+ * Doc update to clarify how text and eol attributes interact to
+   specify the end-of-line conversion.
+   (merge 6696077ace ah/doc-attributes-text later to maint).
+
+ * Gitk updates from GfW project.
+   (merge 99e70f3077 js/gitk-fixes-from-gfw later to maint).
+
+ * "git diff --dirstat" leaked memory, which has been plugged.
+   (merge 83973981eb jc/dirstat-plug-leaks later to maint).
+
+ * "git merge-tree" reads the basic configuration, which can be used
+    by git forges to disable replace-refs feature.
+   (merge b6551feadf ds/merge-tree-use-config later to maint).
+
+ * A few bugs in the sequencer machinery that results in miscounting
+   the steps have been corrected.
+   (merge 170eea9750 js/rebase-count-fixes later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge f7111175df as/doc-markup-fix later to maint).
+   (merge 90ff7c9898 fc/test-aggregation-clean-up later to maint).
+   (merge 9b0c7f308a jc/am-doc-refer-to-format-patch later to maint).
+   (merge b10cbdac4c bb/unicode-width-table-15 later to maint).
+   (merge 3457b50e8c ab/retire-scripted-add-p later to maint).
+   (merge d52fcf493b ds/p2000-fix-grep-sparse later to maint).
+   (merge ec063d2591 ss/hashmap-typofix later to maint).
+   (merge 1aaed69d11 rs/archive-mtime later to maint).
+   (merge 2da2cc9b28 ob/rollback-after-commit-lock-failure later to maint).
+   (merge 54dbd0933b ob/sequencer-save-head-simplify later to maint).
+   (merge a93cbe8d78 ar/test-cleanup-unused-file-creation later to maint).
+   (merge cc48ddd937 jk/chainlint-fixes later to maint).
+   (merge 4833b08426 ow/ref-format-remove-unused-member later to maint).
+   (merge d0ea2ca1cf dw/doc-submittingpatches-grammofix later to maint).
+   (merge fd72637423 ar/t2024-checkout-output-fix later to maint).
+   (merge d45cbe3fe0 ob/sequencer-i18n-fix later to maint).
+   (merge b734fe49fd ob/messages-capitalize-exception later to maint).
+   (merge ad353d7e77 ma/gittutorial-fixes later to maint).
+   (merge a5855fd8d4 ar/test-cleanup-unused-file-creation-part2 later to maint).
+   (merge 0c5308af30 sd/doc-gitignore-and-rm-cached later to maint).
+   (merge cbb83daeaf kh/doc-interpret-trailers-updates later to maint).
+   (merge 3d77fbb664 ar/config-count-tests-updates later to maint).
+   (merge b7cf25c8f4 jc/t9800-fix-use-of-show-s-raw later to maint).
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).
index 927f7329a557bab6c316fa8fa1e478fa54b7e6a7..973d7a81d4492d627c77ce3c6db105ae917fb957 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 to 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.
@@ -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]]
@@ -543,7 +602,7 @@ trigger a new CI build to ensure all tests pass.
 [[mua]]
 == MUA specific hints
 
-Some of patches I receive or pick up from the list share common
+Some of the patches I receive or pick up from the list share common
 patterns of breakage.  Please make sure your MUA is set up
 properly not to corrupt whitespaces.
 
index 3e4c13971b4a7c02a769e87685331822c844e238..60f76f43edab759a5587835fc5cb58ce0d8a7b4d 100644 (file)
@@ -51,25 +51,6 @@ ifdef::doctype-manpage[]
 endif::doctype-manpage[]
 endif::backend-docbook[]
 
-ifdef::doctype-manpage[]
-ifdef::backend-docbook[]
-[header]
-template::[header-declarations]
-<refentry>
-<refmeta>
-<refentrytitle>{mantitle}</refentrytitle>
-<manvolnum>{manvolnum}</manvolnum>
-<refmiscinfo class="source">{mansource}</refmiscinfo>
-<refmiscinfo class="version">{manversion}</refmiscinfo>
-<refmiscinfo class="manual">{manmanual}</refmiscinfo>
-</refmeta>
-<refnamediv>
-  <refname>{manname}</refname>
-  <refpurpose>{manpurpose}</refpurpose>
-</refnamediv>
-endif::backend-docbook[]
-endif::doctype-manpage[]
-
 ifdef::backend-xhtml11[]
 [attributes]
 git-relative-html-prefix=
index 9a663535f443c0f46a0a244c4dc454acdf5ffdef..552dcc60f2a41e24260fd4f6f8d6090a3df660e1 100644 (file)
@@ -64,11 +64,9 @@ include::line-range-format.txt[]
        manual page.
 
 --contents <file>::
-       When <rev> is not specified, the command annotates the
-       changes starting backwards from the working tree copy.
-       This flag makes the command pretend as if the working
-       tree copy has the contents of the named file (specify
-       `-` to make the command read from the standard input).
+       Annotate using the contents from the named file, starting from <rev>
+       if it is specified, and HEAD otherwise. You may specify '-' to make
+       the command read from the standard input for the file contents.
 
 --date <format>::
        Specifies the format used to output dates. If --date is not
index 0e93aef86264dbe5c7af33e66a13778c160b24ba..229b63a454c035dcd6fa6797b29788ae67c053a4 100644 (file)
@@ -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.
 
index a00d0100a82ba710ea52470764b047e2aeb38d56..c548a91e6761c762b19f26e2bb1f5a36f8192ba9 100644 (file)
@@ -136,4 +136,10 @@ advice.*::
                Advice shown when either linkgit:git-add[1] or linkgit:git-rm[1]
                is asked to update index entries outside the current sparse
                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 a3f821121020c0b6a4c66fd74ad52a974ac07207..447c40d85a289dbb58397d9c9f1e2875084a0f50 100644 (file)
@@ -34,3 +34,10 @@ See the `--trust-exit-code` option in linkgit:git-difftool[1] for more details.
 
 difftool.prompt::
        Prompt before each invocation of the diff tool.
+
+difftool.guiDefault::
+       Set `true` to use the `diff.guitool` by default (equivalent to specifying
+       the `--gui` argument), or `auto` to select `diff.guitool` or `diff.tool`
+       depending on the presence of a `DISPLAY` environment variable value. The
+       default is `false`, where the `--gui` argument must be provided
+       explicitly for the `diff.guitool` to be used.
index e52bc6b858470c60f09f52d4f9d2b9f17135483c..bf9546fca4f693f01b39252d12def7df9b51a52f 100644 (file)
@@ -15,8 +15,8 @@ feature.experimental::
 * `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
 skipping more commits at a time, reducing the number of round trips.
 +
-* `gc.cruftPacks=true` reduces disk space used by unreachable objects during
-garbage collection, preventing loose object explosions.
+* `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 73678d88a1dba172c43f4fb850e750c6a0c7f96c..8cf6f00d9365cf19b6244ba005d078c5ebed8a05 100644 (file)
@@ -144,3 +144,10 @@ will only show notes from `refs/notes/bar`.
 format.mboxrd::
        A boolean value which enables the robust "mboxrd" format when
        `--stdout` is in use to escape "^>+From " lines.
+
+format.noprefix::
+       If set, do not show any source or destination prefix in patches.
+       This is equivalent to the `diff.noprefix` option used by `git
+       diff` (but which is not respected by `format-patch`). Note that
+       by setting this, the receiver of any patches you generate will
+       have to apply them using the `-p0` option.
index 38fea076a26d0f1f7bf137723baba945675901fc..ca47eb200882a251ddf7ad644151bb6e896b242f 100644 (file)
@@ -43,11 +43,11 @@ gc.autoDetach::
        if the system supports it. Default is true.
 
 gc.bigPackThreshold::
-       If non-zero, all packs larger than this limit are kept when
-       `git gc` is run. This is very similar to `--keep-largest-pack`
-       except that all packs that meet the threshold are kept, not
-       just the largest pack. Defaults to zero. Common unit suffixes of
-       'k', 'm', or 'g' are supported.
+       If non-zero, all non-cruft packs larger than this limit are kept
+       when `git gc` is run. This is very similar to
+       `--keep-largest-pack` except that all non-cruft packs that meet
+       the threshold are kept, not just the largest pack. Defaults to
+       zero. Common unit suffixes of 'k', 'm', or 'g' are supported.
 +
 Note that if the number of kept packs is more than gc.autoPackLimit,
 this configuration variable is ignored, all packs except the base pack
@@ -84,7 +84,7 @@ gc.packRefs::
 gc.cruftPacks::
        Store unreachable objects in a cruft pack (see
        linkgit:git-repack[1]) instead of as loose objects. The default
-       is `false`.
+       is `true`.
 
 gc.pruneExpire::
        When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
@@ -130,6 +130,21 @@ 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.rerereResolved::
        Records of conflicted merge you resolved earlier are
        kept for this many days when 'git rerere gc' is run.
index afeeccfbfa7a7073a19088a625b03fe2abee5801..51a70781e58cf9923cb0b1b84104c6d011dbd5f8 100644 (file)
@@ -246,8 +246,9 @@ significantly since the entire buffer is allocated even for small
 pushes.
 
 http.lowSpeedLimit, http.lowSpeedTime::
-       If the HTTP transfer speed is less than 'http.lowSpeedLimit'
-       for longer than 'http.lowSpeedTime' seconds, the transfer is aborted.
+       If the HTTP transfer speed, in bytes per second, is less than
+       'http.lowSpeedLimit' for longer than 'http.lowSpeedTime' seconds,
+       the transfer is aborted.
        Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and
        `GIT_HTTP_LOW_SPEED_TIME` environment variables.
 
index e779a122d8a78f10adb6381a9d00e9041b2c5b70..56a7eeeffb4336ec05c52e96df59b501a41460bf 100644 (file)
@@ -85,3 +85,10 @@ mergetool.writeToTemp::
 
 mergetool.prompt::
        Prompt before each invocation of the merge resolution program.
+
+mergetool.guiDefault::
+       Set `true` to use the `merge.guitool` by default (equivalent to
+       specifying the `--gui` argument), or `auto` to select `merge.guitool`
+       or `merge.tool` depending on the presence of a `DISPLAY` environment
+       variable value. The default is `false`, where the `--gui` argument
+       must be provided explicitly for the `merge.guitool` to be used.
index 53093d99969cc090e4727a570eb667a6fba445d4..3748136d141e4193682655559d91f143f31305ec 100644 (file)
@@ -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
@@ -171,9 +188,15 @@ pack.writeBitmapLookupTable::
        beneficial in repositories that have relatively large bitmap
        indexes. Defaults to false.
 
+pack.readReverseIndex::
+       When true, git will read any .rev file(s) that may be available
+       (see: linkgit:gitformat-pack[5]). When false, the reverse index
+       will be generated from scratch and stored in memory. Defaults to
+       true.
+
 pack.writeReverseIndex::
        When true, git will write a corresponding .rev file (see:
        linkgit:gitformat-pack[5])
        for each new packfile that it writes in all places except for
        linkgit:git-fast-import[1] and in the bulk checkin mechanism.
-       Defaults to false.
+       Defaults to true.
index f19bd0e04079051d6be21ee461d1a98c9a632629..9c248accec2c5d572cf11f26ffcbfe8e7eab1465 100644 (file)
@@ -67,3 +67,19 @@ rebase.rescheduleFailedExec::
 
 rebase.forkPoint::
        If set to false set `--no-fork-point` option by default.
+
+rebase.rebaseMerges::
+       Whether and how to set the `--rebase-merges` option by default. Can
+       be `rebase-cousins`, `no-rebase-cousins`, or a boolean. Setting to
+       true or to `no-rebase-cousins` is equivalent to
+       `--rebase-merges=no-rebase-cousins`, setting to `rebase-cousins` is
+       equivalent to `--rebase-merges=rebase-cousins`, and setting to false is
+       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 51da7088a844d3f148d78317e792efd485a2c0af..92a9ebe98c63e5fe75eb98237543d41d9f15c502 100644 (file)
@@ -61,6 +61,7 @@ sendemail.ccCmd::
 sendemail.chainReplyTo::
 sendemail.envelopeSender::
 sendemail.from::
+sendemail.headerCmd::
 sendemail.signedoffbycc::
 sendemail.smtpPass::
 sendemail.suppresscc::
index 7d73e976d9936bb35981ad7f64b0af66865491b8..c07488b123c63111a84c027b4d80720383dc82b8 100644 (file)
@@ -22,21 +22,18 @@ 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[]
@@ -852,6 +849,11 @@ endif::git-format-patch[]
 --no-prefix::
        Do not show any source or destination prefix.
 
+--default-prefix::
+       Use the default source and destination prefixes ("a/" and "b/").
+       This is usually the default already, but may be used to override
+       config such as `diff.noprefix`.
+
 --line-prefix=<prefix>::
        Prepend an additional prefix to every line of output.
 
index 1694300e50bfcfa58cc7798614a254fec2e219a5..fb09e0ac0ebcac9f88a0fbe08c258398586ba0fe 100755 (executable)
@@ -153,7 +153,7 @@ render_tree () {
                make -j$parallel -C "$tmp/worktree" \
                        $makemanflags \
                        GIT_VERSION=omitted \
-                       SOURCE_DATE_EPOCH=0 \
+                       GIT_DATE=1970-01-01 \
                        DESTDIR="$tmp/installed/$dname+" \
                        install-man &&
                mv "$tmp/installed/$dname+" "$tmp/installed/$dname"
index 622bd84768b056e23fa0f432e745aaffd651c734..41fc7ca3c67f5d31d5a771de906394480f265d9f 100644 (file)
@@ -78,6 +78,13 @@ linkgit:git-config[1].
 --dry-run::
        Show what would be done, without making any changes.
 
+--porcelain::
+       Print the output to standard output in an easy-to-parse format for
+       scripts. See section OUTPUT in linkgit:git-fetch[1] for details.
++
+This is incompatible with `--recurse-submodules=[yes|on-demand]` and takes
+precedence over the `fetch.output` config option.
+
 ifndef::git-pull[]
 --[no-]write-fetch-head::
        Write the list of remote refs fetched in the `FETCH_HEAD`
index 0c1dfb3c98b440f87e561a0d44c240a41d80dc14..900be198b14e933d19f87febd9860cb0c67a6bf0 100644 (file)
@@ -24,7 +24,9 @@ DESCRIPTION
 -----------
 Splits mail messages in a mailbox into commit log message,
 authorship information and patches, and applies them to the
-current branch.
+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.
 
 OPTIONS
 -------
@@ -273,7 +275,8 @@ include::config/am.txt[]
 
 SEE ALSO
 --------
-linkgit:git-apply[1].
+linkgit:git-apply[1],
+linkgit:git-format-patch[1].
 
 GIT
 ---
index fbb39fbdf5d62a455c8b62d4870817998d0434ad..7872dba3aefa3de62175f0e88bfac1473bbe0723 100644 (file)
@@ -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 4400a17330b4204227050b76d380bc84b017628a..f69a871a96f7589015c723ccdfdd95c6c1d610ed 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
            [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
            [--ignore-rev <rev>] [--ignore-revs-file <file>]
            [--color-lines] [--color-by-age] [--progress] [--abbrev=<n>]
-           [<rev> | --contents <file> | --reverse <rev>..<rev>] [--] <file>
+           [ --contents <file> ] [<rev> | --reverse <rev>..<rev>] [--] <file>
 
 DESCRIPTION
 -----------
index d382ac69f77b1ce607d881f149a04f94aa930d82..d207da9101a5cfe6441a03360191d3b6b8a73a46 100644 (file)
@@ -156,6 +156,10 @@ in another worktree linked to the same repository.
 --ignore-case::
        Sorting and filtering branches are case insensitive.
 
+--omit-empty::
+       Do not print a newline after formatted refs where the format expands
+       to the empty string.
+
 --column[=<options>]::
 --no-column::
        Display branch listing in columns. See configuration variable
index 18a022b4b40c345040c23e83bed1fd1983bd725e..3ab42a19cae4aca0e6a3a83db92d25a4d88bf927 100644 (file)
@@ -9,7 +9,7 @@ git-bundle - Move objects and refs by archive
 SYNOPSIS
 --------
 [verse]
-'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied]
+'git bundle' create [-q | --quiet | --progress]
                    [--version=<version>] <file> <git-rev-list-args>
 'git bundle' verify [-q | --quiet] <file>
 'git bundle' list-heads <file> [<refname>...]
@@ -66,7 +66,7 @@ create [options] <file> <git-rev-list-args>::
        Used to create a bundle named 'file'.  This requires the
        '<git-rev-list-args>' arguments to define the bundle contents.
        'options' contains the options specific to the 'git bundle create'
-       subcommand.
+       subcommand. If 'file' is `-`, the bundle is written to stdout.
 
 verify <file>::
        Used to check that a bundle file is valid and will apply
@@ -77,12 +77,13 @@ verify <file>::
        Finally, information about additional capabilities, such as "object
        filter", is printed. See "Capabilities" in linkgit:gitformat-bundle[5]
        for more information. The exit code is zero for success, but will
-       be nonzero if the bundle file is invalid.
+       be nonzero if the bundle file is invalid. If 'file' is `-`, the
+       bundle is read from stdin.
 
 list-heads <file>::
        Lists the references defined in the bundle.  If followed by a
        list of references, only references matching those given are
-       printed out.
+       printed out. If 'file' is `-`, the bundle is read from stdin.
 
 unbundle <file>::
        Passes the objects in the bundle to 'git index-pack'
@@ -90,6 +91,7 @@ unbundle <file>::
        defined references. If a list of references is given, only
        references matching those in the list are printed. This command is
        really plumbing, intended to be called only by 'git fetch'.
+       If 'file' is `-`, the bundle is read from stdin.
 
 <git-rev-list-args>::
        A list of arguments, acceptable to 'git rev-parse' and
@@ -115,22 +117,6 @@ unbundle <file>::
        is specified. This flag forces progress status even if
        the standard error stream is not directed to a terminal.
 
---all-progress::
-       When --stdout is specified then progress report is
-       displayed during the object count and compression phases
-       but inhibited during the write-out phase. The reason is
-       that in some cases the output stream is directly linked
-       to another command which may wish to display progress
-       status of its own as it processes incoming pack data.
-       This flag is like --progress except that it forces progress
-       report for the write-out phase as well even if --stdout is
-       used.
-
---all-progress-implied::
-       This is used to imply --all-progress whenever progress display
-       is activated.  Unlike --all-progress this flag doesn't actually
-       force any progress display by itself.
-
 --version=<version>::
        Specify the bundle version.  Version 2 is the older format and can only be
        used with SHA-1 repositories; the newer version 3 contains capabilities that
index 411de2e27ddc0db762ec9be6ceec18a7fc1bf069..0e4936d182632fb3362376787efd7d633bd623d2 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
 'git cat-file' (-t | -s) [--allow-unknown-type] <object>
 'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
             [--buffer] [--follow-symlinks] [--unordered]
-            [--textconv | --filters] [-z]
+            [--textconv | --filters] [-Z]
 'git cat-file' (--textconv | --filters)
             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
 
@@ -243,10 +243,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 +390,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 6bb32ab4602aa9b55c935a0d3bb64d56682c7bed..4af0904f4729b463d3b63bf3479f5e4b313773fd 100644 (file)
@@ -483,14 +483,11 @@ $ git checkout -b foo  # or "git switch -c foo"  <1>
 $ git branch foo                                 <2>
 $ git tag foo                                    <3>
 ------------
-
 <1> creates a new branch `foo`, which refers to commit `f`, and then
     updates `HEAD` to refer to branch `foo`. In other words, we'll no longer
     be in detached `HEAD` state after this command.
-
 <2> similarly creates a new branch `foo`, which refers to commit `f`,
     but leaves `HEAD` detached.
-
 <3> creates a new tag `foo`, which refers to commit `f`,
     leaving `HEAD` detached.
 
@@ -519,84 +516,89 @@ to checkout these paths out of the index.
 EXAMPLES
 --------
 
-. The following sequence checks out the `master` branch, reverts
-  the `Makefile` to two revisions back, deletes `hello.c` by
-  mistake, and gets it back from the index.
-+
+=== 1. Paths
+
+The following sequence checks out the `master` branch, reverts
+the `Makefile` to two revisions back, deletes `hello.c` by
+mistake, and gets it back from the index.
+
 ------------
 $ git checkout master             <1>
 $ git checkout master~2 Makefile  <2>
 $ rm -f hello.c
 $ git checkout hello.c            <3>
 ------------
-+
 <1> switch branch
 <2> take a file out of another commit
 <3> restore `hello.c` from the index
-+
+
 If you want to check out _all_ C source files out of the index,
 you can say
-+
+
 ------------
 $ git checkout -- '*.c'
 ------------
-+
+
 Note the quotes around `*.c`.  The file `hello.c` will also be
 checked out, even though it is no longer in the working tree,
 because the file globbing is used to match entries in the index
 (not in the working tree by the shell).
-+
+
 If you have an unfortunate branch that is named `hello.c`, this
 step would be confused as an instruction to switch to that branch.
 You should instead write:
-+
+
 ------------
 $ git checkout -- hello.c
 ------------
 
-. After working in the wrong branch, switching to the correct
-  branch would be done using:
-+
+=== 2. Merge
+
+After working in the wrong branch, switching to the correct
+branch would be done using:
+
 ------------
 $ git checkout mytopic
 ------------
-+
+
 However, your "wrong" branch and correct `mytopic` branch may
 differ in files that you have modified locally, in which case
 the above checkout would fail like this:
-+
+
 ------------
 $ git checkout mytopic
 error: You have local changes to 'frotz'; not switching branches.
 ------------
-+
+
 You can give the `-m` flag to the command, which would try a
 three-way merge:
-+
+
 ------------
 $ git checkout -m mytopic
 Auto-merging frotz
 ------------
-+
+
 After this three-way merge, the local modifications are _not_
 registered in your index file, so `git diff` would show you what
 changes you made since the tip of the new branch.
 
-. When a merge conflict happens during switching branches with
-  the `-m` option, you would see something like this:
-+
+=== 3. Merge conflict
+
+When a merge conflict happens during switching branches with
+the `-m` option, you would see something like this:
+
 ------------
 $ git checkout -m mytopic
 Auto-merging frotz
 ERROR: Merge conflict in frotz
 fatal: merge program failed
 ------------
-+
+
 At this point, `git diff` shows the changes cleanly merged as in
 the previous example, as well as the changes in the conflicted
 files.  Edit and resolve the conflict and mark it resolved with
 `git add` as usual:
-+
+
 ------------
 $ edit frotz
 $ git add frotz
index d6434d262d6e2945ffe98f397ab8500a53990750..c37c4a37f7412c0b712d14067c2d7c7d975933c5 100644 (file)
@@ -58,6 +58,11 @@ never use the local optimizations).  Specifying `--no-local` will
 override the default when `/path/to/repo` is given, using the regular
 Git transport instead.
 +
+If the repository's `$GIT_DIR/objects` has symbolic links or is a
+symbolic link, the clone will fail. This is a security measure to
+prevent the unintentional copying of files by dereferencing the symbolic
+links.
++
 *NOTE*: this operation can race with concurrent modification to the
 source repository, similar to running `cp -r src dst` while modifying
 `src`.
index 29d184ab82420c3177b11df875e38efa016a01d9..a220afed4f35ba2a2ea1d7bd68dd07b1353d3522 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.
 
@@ -113,7 +113,13 @@ separated by an `=` (equals) sign, followed by a newline.
 The key may contain any bytes except `=`, newline, or NUL. The value may
 contain any bytes except newline or NUL.
 
-In both cases, all bytes are treated as-is (i.e., there is no quoting,
+Attributes with keys that end with C-style array brackets `[]` can have
+multiple values. Each instance of a multi-valued attribute forms an
+ordered list of values - the order of the repeated attributes defines
+the order of the values. An empty multi-valued attribute (`key[]=\n`)
+acts to clear any previous entries and reset the list.
+
+In all cases, all bytes are treated as-is (i.e., there is no quoting,
 and one cannot transmit a value with newline or NUL in it). The list of
 attributes is terminated by a blank line or end-of-file.
 
@@ -150,6 +156,12 @@ Git understands the following attributes:
        When reading credentials from helpers, `git credential fill` ignores expired
        passwords. Represented as Unix time UTC, seconds since 1970.
 
+`oauth_refresh_token`::
+
+       An OAuth refresh token may accompany a password that is an OAuth access
+       token. Helpers must treat this attribute as confidential like the password
+       attribute. Git itself has no special behaviour for this attribute.
+
 `url`::
 
        When this special attribute is read by `git credential`, the
@@ -166,6 +178,17 @@ empty string.
 Components which are missing from the URL (e.g., there is no
 username in the example above) will be left unset.
 
+`wwwauth[]`::
+
+       When an HTTP response is received by Git that includes one or more
+       'WWW-Authenticate' authentication headers, these will be passed by Git
+       to credential helpers.
++
+Each 'WWW-Authenticate' header value is passed as a multi-valued
+attribute 'wwwauth[]', where the order of the attributes is the same as
+they appear in the HTTP response. This attribute is 'one-way' from Git
+to pass additional information to credential helpers.
+
 Unrecognised attributes are silently discarded.
 
 GIT
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 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 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 9d14c3c9f099aab8d225767ef6d308ecee2e6713..ac0ac6fa02205a5946beaafc538c0764bee85cb4 100644 (file)
@@ -97,10 +97,12 @@ instead.  `--no-symlinks` is the default on Windows.
 --[no-]gui::
        When 'git-difftool' is invoked with the `-g` or `--gui` option
        the default diff tool will be read from the configured
-       `diff.guitool` variable instead of `diff.tool`. The `--no-gui`
-       option can be used to override this setting. If `diff.guitool`
-       is not set, we will fallback in the order of `merge.guitool`,
-       `diff.tool`, `merge.tool` until a tool is found.
+       `diff.guitool` variable instead of `diff.tool`. This may be
+       selected automatically using the configuration variable
+       `difftool.guiDefault`. The `--no-gui` option can be used to
+       override these settings. If `diff.guitool` is not set, we will
+       fallback in the order of `merge.guitool`, `diff.tool`,
+       `merge.tool` until a tool is found.
 
 --[no-]trust-exit-code::
        'git-difftool' invokes a diff tool individually on each file.
index fba66f14607a5f3f70e87e3fa1d04af90015a277..f123139c581001d2bcbd94dcc187775e58e8fd6c 100644 (file)
@@ -204,6 +204,15 @@ representing the status of a single ref. Each line is of the form:
  <flag> <summary> <from> -> <to> [<reason>]
 -------------------------------
 
+When using `--porcelain`, the output format is intended to be
+machine-parseable. In contrast to the human-readable output formats it
+thus prints to standard output instead of standard error. Each line is
+of the form:
+
+-------------------------------
+<flag> <old-object-id> <new-object-id> <local-reference>
+-------------------------------
+
 The status of up-to-date refs is shown only if the --verbose option is
 used.
 
index 6da899c62964275a97854c0b338f83f51db4bdfe..11b2bc3121626d047b415f805e98b380be0ef1e4 100644 (file)
@@ -9,10 +9,12 @@ SYNOPSIS
 --------
 [verse]
 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
-                  [(--sort=<key>)...] [--format=<format>] [<pattern>...]
+                  [(--sort=<key>)...] [--format=<format>]
+                  [ --stdin | <pattern>... ]
                   [--points-at=<object>]
                   [--merged[=<object>]] [--no-merged[=<object>]]
                   [--contains[=<object>]] [--no-contains[=<object>]]
+                  [--exclude=<pattern> ...]
 
 DESCRIPTION
 -----------
@@ -32,6 +34,10 @@ OPTIONS
        literally, in the latter case matching completely or from the
        beginning up to a slash.
 
+--stdin::
+       If `--stdin` is supplied, then the list of patterns is read from
+       standard input instead of from the argument list.
+
 --count=<count>::
        By default the command shows all refs that match
        `<pattern>`.  This option makes it stop after showing
@@ -93,6 +99,15 @@ OPTIONS
 --ignore-case::
        Sorting and filtering refs are case insensitive.
 
+--omit-empty::
+       Do not print a newline after formatted refs where the format expands
+       to the empty string.
+
+--exclude=<pattern>::
+       If one or more patterns are given, only refs which do not match
+       any excluded pattern(s) are shown. Matching is done using the
+       same rules as `<pattern>` above.
+
 FIELD NAMES
 -----------
 
@@ -212,11 +227,66 @@ 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
        otherwise.
 
+ahead-behind:<committish>::
+       Two integers, separated by a space, demonstrating the number of
+       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.
index dfcc7da4c211706570cd1ce7e1fd8552fb8947d9..373b46fc0de64f4c7426f683b95f24f95ff9cd84 100644 (file)
@@ -99,7 +99,7 @@ To omit patch numbers from the subject, use `-N`.
 
 If given `--thread`, `git-format-patch` will generate `In-Reply-To` and
 `References` headers to make the second and subsequent patch mails appear
-as replies to the first mail; this also generates a `Message-Id` header to
+as replies to the first mail; this also generates a `Message-ID` header to
 reference.
 
 OPTIONS
@@ -163,7 +163,7 @@ include::diff-options.txt[]
 --no-thread::
        Controls addition of `In-Reply-To` and `References` headers to
        make the second and subsequent mails appear as replies to the
-       first.  Also controls generation of the `Message-Id` header to
+       first.  Also controls generation of the `Message-ID` header to
        reference.
 +
 The optional <style> argument can be either `shallow` or `deep`.
@@ -173,8 +173,7 @@ series, where the head is chosen from the cover letter, the
 threading makes every mail a reply to the previous one.
 +
 The default is `--no-thread`, unless the `format.thread` configuration
-is set.  If `--thread` is specified without a style, it defaults to the
-style specified by `format.thread` if any, or else `shallow`.
+is set.  `--thread` without an argument is equivalent to `--thread=shallow`.
 +
 Beware that the default for 'git send-email' is to thread emails
 itself.  If you want `git format-patch` to take care of threading, you
@@ -246,7 +245,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 a65c9aa62d64112dfd03335af82a680e54d00c58..90806fd26aa4ac0d1fef93d25384af3799818896 100644 (file)
@@ -54,9 +54,10 @@ other housekeeping tasks (e.g. rerere, working trees, reflog...) will
 be performed as well.
 
 
---cruft::
+--[no-]cruft::
        When expiring unreachable objects, pack them separately into a
-       cruft pack instead of storing them as loose objects.
+       cruft pack instead of storing them as loose objects. `--cruft`
+       is on by default.
 
 --prune=<date>::
        Prune loose objects older than date (default is 2 weeks ago,
@@ -77,9 +78,10 @@ be performed as well.
        instance running on this repository.
 
 --keep-largest-pack::
-       All packs except the largest pack and those marked with a
-       `.keep` files are consolidated into a single pack. When this
-       option is used, `gc.bigPackThreshold` is ignored.
+       All packs except the largest non-cruft pack, any packs marked
+       with a `.keep` file, and any cruft pack(s) are consolidated into
+       a single pack. When this option is used, `gc.bigPackThreshold`
+       is ignored.
 
 AGGRESSIVE
 ----------
index 472b5bb995be278415daede21a5489ed2d4c01da..8577f7a7d4087d347bddf39b45c9c5365e2dafa6 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.
index 22ff3a603e03e3c9a1f0d76918fafa225989079d..55d89614661c5c46c8dd69fb149cfec70d72fc85 100644 (file)
@@ -14,21 +14,38 @@ SYNOPSIS
 
 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.
 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.
+`--trailer` option, if any, to 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
@@ -36,41 +53,46 @@ 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
 to remove starting and trailing whitespace, and the resulting trimmed
-<token> and <value> will appear in the message like this:
+<token> and <value> will appear in the output like this:
 
 ------------------------------------------------
 token: value
 ------------------------------------------------
 
 This means that the trimmed <token> and <value> will be separated by
-`': '` (one colon followed by one space).
+`': '` (one colon followed by one space). For convenience, the <token> can be a
+shortened string key (e.g., "sign") instead of the full string which should
+appear before the separator on the output (e.g., "Signed-off-by"). This can be
+configured using the 'trailer.<token>.key' configuration variable.
 
 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
+<token>, but any number of regular space and tab characters are allowed
+between the <token> and the separator. There can be whitespaces before,
+inside or after the <value>. The <value> may be split over multiple lines
 with each subsequent line starting with at least one whitespace, like
-the "folding" in RFC 822.
+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.
+------------------------------------------------
+token: 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,12 +101,12 @@ 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 to the inputs. See the description of this
        command.
 
 --where <placement>::
@@ -98,7 +120,7 @@ OPTIONS
 --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
+       least one trailer with the same <token> in the input.  A setting
        provided with '--if-exists' overrides all configuration variables
        and applies to all '--trailer' options until the next occurrence of
        '--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`,
@@ -107,7 +129,7 @@ OPTIONS
 --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
+       trailer with the same <token> in the input.  A setting
        provided with '--if-missing' overrides all configuration variables
        and applies to all '--trailer' options until the next occurrence of
        '--if-missing' or '--no-if-missing'. Possible actions are `doNothing`
@@ -174,7 +196,7 @@ first trailer with the same <token>.
 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 <token> in the input.
 +
 The valid values for this option are: `addIfDifferentNeighbor` (this
 is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
@@ -184,10 +206,10 @@ trailer with the same (<token>, <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 (<token>, <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 (<token>, <value>) pair are already in the input.
 +
 With `replace`, an existing trailer with the same <token> will be
 deleted and the new trailer will be added. The deleted trailer will be
@@ -195,12 +217,12 @@ the closest one (with the same <token>) 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 <token> 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.
+       <token> in the input.
 +
 The valid values for this option are: `add` (this is the default) and
 `doNothing`.
@@ -235,13 +257,13 @@ trailer.<token>.ifmissing::
        that option for trailers with the specified <token>.
 
 trailer.<token>.command::
+       Deprecated in favor of 'trailer.<token>.cmd'.
        This option behaves in the same way as 'trailer.<token>.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
@@ -249,10 +271,10 @@ 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:
+       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.
+       called each time a '--trailer <token>=<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
@@ -272,37 +294,37 @@ 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
-$ cat msg.txt | git interpret-trailers --trailer 'sign: Alice <alice@example.com>' --trailer 'sign: Bob <bob@example.com>'
+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>
@@ -322,17 +344,30 @@ $ git interpret-trailers --trailer 'Cc: Alice <alice@example.com>' --trailer 'Re
   'Signed-off-by: ' already, and show how it works:
 +
 ------------
+$ cat msg1.txt
+subject
+
+body text
 $ git config trailer.sign.key "Signed-off-by: "
 $ git config trailer.sign.ifmissing add
 $ git config trailer.sign.ifexists doNothing
-$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
-$ git interpret-trailers <<EOF
-> EOF
+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"'
+$ git interpret-trailers --trailer sign <msg1.txt
+subject
+
+body text
 
 Signed-off-by: Bob <bob@example.com>
-$ git interpret-trailers <<EOF
-> Signed-off-by: Alice <alice@example.com>
-> EOF
+$ cat msg2.txt
+subject
+
+body text
+
+Signed-off-by: Alice <alice@example.com>
+$ git interpret-trailers --trailer sign <msg2.txt
+subject
+
+body text
 
 Signed-off-by: Alice <alice@example.com>
 ------------
@@ -357,18 +392,17 @@ Fix #42
 $ cat ~/bin/glog-find-author
 #!/bin/sh
 test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true
+$ cat msg.txt
+subject
+
+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" <<EOF
-> subject
->
-> message
->
-> EOF
+$ 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>
@@ -382,18 +416,17 @@ Helped-by: Christian Couder <christian.couder@gmail.com>
 $ cat ~/bin/glog-grep
 #!/bin/sh
 test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
+$ cat msg.txt
+subject
+
+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." <<EOF
-> subject
->
-> message
->
-> EOF
+$ git interpret-trailers --trailer="ref:Add copyright notices." <msg.txt
 subject
 
-message
+body text
 
 Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
 ------------
@@ -402,20 +435,23 @@ Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
   commit that is related, and show how it works:
 +
 ------------
+$ cat msg.txt
+subject
+
+body text
+
+see: HEAD~2
+$ cat ~/bin/glog-ref
+#!/bin/sh
+git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14
 $ git config trailer.see.key "See-also: "
 $ git config trailer.see.ifExists "replace"
 $ git config trailer.see.ifMissing "doNothing"
-$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG"
-$ git interpret-trailers <<EOF
-> subject
-> 
-> message
-> 
-> see: HEAD~2
-> EOF
+$ 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)
 ------------
@@ -427,22 +463,21 @@ See-also: fe3187489d69c4 (subject of related commit)
   to add a 'git-version' trailer:
 +
 ------------
-$ sed -e 's/ Z$/ /' >commit_template.txt <<EOF
-***subject***
-> 
-***message***
-> 
-Fixes: Z
-Cc: Z
-Reviewed-by: Z
-Signed-off-by: Z
-> EOF
+$ cat temp.txt
+***subject***
+
+***message***
+
+Fixes: Z
+Cc: Z
+Reviewed-by: Z
+Signed-off-by: Z
+$ sed -e 's/ Z$/ /' temp.txt > commit_template.txt
 $ git config commit.template commit_template.txt
-$ cat >.git/hooks/commit-msg <<EOF
-> #!/bin/sh
-> git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
-> mv "\$1.new" "\$1"
-> EOF
+$ cat .git/hooks/commit-msg
+#!/bin/sh
+git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
+mv "\$1.new" "\$1"
 $ chmod +x .git/hooks/commit-msg
 ------------
 
index 1abdd3c21c513c3c9f547e25c83d212ba1866b2b..1bc0328bb789283461bc1b7143830a6d88e06eb0 100644 (file)
@@ -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 88ee942101a7748ac2a7b5030b364ed7e27d5fdb..ffc4fbf7e89a89b075bb00bafcb041c19adc271f 100644 (file)
@@ -108,7 +108,7 @@ This is an integer status followed by a NUL character.  The integer status is:
 
      0: merge had conflicts
      1: merge was clean
-     &lt;0: something prevented the merge from running (e.g. access to repository
+     <0: something prevented the merge from running (e.g. access to repository
         objects denied by filesystem)
 
 [[OIDTLT]]
index 0aeff572a59d8fea319f334232deae4a9df4e464..8625c5cb0ec2d31ac264789d80a80b6c5a0c38b9 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`.
@@ -336,7 +340,8 @@ You can work through the conflict with a number of tools:
 
  * 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 c44e205629bf521fbb97c2b49493fcc9b9450932..07535f6576e81a936c3b65481de7d1b53c4120a8 100644 (file)
@@ -85,12 +85,13 @@ success of the resolution after the custom tool has exited.
        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
-       configured under `merge.tool`.
+       configured under `merge.tool`. This may be autoselected using
+       the configuration variable `mergetool.guiDefault`.
 
 --no-gui::
-       This overrides a previous `-g` or `--gui` setting and reads the
-       default merge tool will be read from the configured `merge.tool`
-       variable.
+       This overrides a previous `-g` or `--gui` setting or
+       `mergetool.guiDefault` configuration and reads the default merge
+       tool from the configured `merge.tool` variable.
 
 -O<orderfile>::
        Process files in the order specified in the
index 466a69751910e4d7d031725f8d52d41d1e7f98a3..b2a2e80d42143a928380bf93e98ac6203442fcc8 100644 (file)
@@ -33,7 +33,7 @@ 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
 
index ec8a27ce8bf8d689bb5f64554dd5426ce38262c0..5c56c870253505395ce3a68216b5b9d329fb02e0 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git name-rev' [--tags] [--refs=<pattern>]
-              ( --all | --stdin | <commit-ish>... )
+              ( --all | --annotate-stdin | <commit-ish>... )
 
 DESCRIPTION
 -----------
@@ -46,7 +46,8 @@ OPTIONS
        Transform stdin by substituting all the 40-character SHA-1
        hexes (say $hex) with "$hex ($rev_name)".  When used with
        --name-only, substitute with "$rev_name", omitting $hex
-       altogether.
+       altogether. This option was called `--stdin` in older versions
+       of Git.
 +
 For example:
 +
@@ -70,10 +71,6 @@ The full name after substitution is master,
 while its tree object is 70d105cc79e63b81cfdcb08a15297c23e60b07ad
 -----------
 
---stdin::
-       This option is deprecated in favor of 'git name-rev --annotate-stdin'.
-       They are functionally equivalent.
-
 --name-only::
        Instead of printing both the SHA-1 and the name, print only
        the name.  If given with --tags the usual tag prefix of
@@ -107,7 +104,7 @@ Now you are wiser, because you know that it happened 940 revisions before v0.99.
 Another nice thing you can do is:
 
 ------------
-% git log | git name-rev --stdin
+% git log | git name-rev --annotate-stdin
 ------------
 
 GIT
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 99ef13839d49cdaa93c1b5a4b523ace18ce454db..13c3eb5ec96c94970171c96f0c503cba418ab1d8 100644 (file)
@@ -11,6 +11,20 @@ SYNOPSIS
 [verse]
 'git pack-redundant' [--verbose] [--alt-odb] (--all | <pack-filename>...)
 
+WARNING
+-------
+`git pack-redundant` has been deprecated and is scheduled for removal in
+a future version of Git. Because it can only remove entire duplicate
+packs and not individual duplicate objects, it is generally not a useful
+tool for reducing repository size. You are better off using `git gc` to
+do so, which will put objects into a new pack, removing duplicates.
+
+Running `pack-redundant` without the `--i-still-use-this` flag will fail
+in this release. If you believe you have a use case for which
+`pack-redundant` is better suited and oppose this removal, please
+contact the Git mailing list at git@vger.kernel.org. More information
+about the list is available at https://git-scm.com/community.
+
 DESCRIPTION
 -----------
 This program computes which packs in your repository
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 dd559a0bcb5111b6107b49f0b78646fb82531e07..5b4edaf4a8dfccec12ba22d131ddce472014219d 100644 (file)
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
 SYNOPSIS
 --------
 [verse]
-'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+'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]
           [-u | --set-upstream] [-o <string> | --push-option=<string>]
           [--[no-]signed|--signed=(true|false|if-asked)]
@@ -147,6 +147,7 @@ already exists on the remote side.
 `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
 
 --all::
+--branches::
        Push all branches (i.e. refs under `refs/heads/`); cannot be
        used with other <refspec>.
 
index 9a295bcee45f4f817c5b319789a32beb22e5f07c..e7b39ad244a4bebc90e9c1974e4239ae771c56d4 100644 (file)
@@ -529,20 +529,25 @@ See also INCOMPATIBLE OPTIONS below.
 
 -r::
 --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
+--no-rebase-merges::
        By default, a rebase will simply drop merge commits from the todo
        list, and put the rebased commits into a single, linear branch.
        With `--rebase-merges`, the rebase will instead try to preserve
        the branching structure within the commits that are to be rebased,
        by recreating the merge commits. Any resolved merge conflicts or
        manual amendments in these merge commits will have to be
-       resolved/re-applied manually.
+       resolved/re-applied manually. `--no-rebase-merges` can be used to
+       countermand both the `rebase.rebaseMerges` config option and a previous
+       `--rebase-merges`.
 +
-By default, or when `no-rebase-cousins` was specified, commits which do not
-have `<upstream>` as direct ancestor will keep their original branch point,
-i.e. commits that would be excluded by linkgit:git-log[1]'s
-`--ancestry-path` option will keep their original ancestry by default. If
-the `rebase-cousins` mode is turned on, such commits are instead rebased
-onto `<upstream>` (or `<onto>`, if specified).
+When rebasing merges, there are two modes: `rebase-cousins` and
+`no-rebase-cousins`. If the mode is not specified, it defaults to
+`no-rebase-cousins`. In `no-rebase-cousins` mode, commits which do not have
+`<upstream>` as direct ancestor will keep their original branch point, i.e.
+commits that would be excluded by linkgit:git-log[1]'s `--ancestry-path`
+option will keep their original ancestry by default. In `rebase-cousins` mode,
+such commits are instead rebased onto `<upstream>` (or `<onto>`, if
+specified).
 +
 It is currently only possible to recreate the merge commits using the
 `ort` merge strategy; different merge strategies can be used only via
index bcd80692870ae002db0bc3c1684c9a0959673964..f26a7591e3737df6bcf190fc26f0fe2bf50fcd83 100644 (file)
@@ -197,10 +197,11 @@ respectively, and they must begin with `refs/` when applied to `--glob`
 or `--all`. If a trailing '/{asterisk}' is intended, it must be given
 explicitly.
 
---exclude-hidden=[receive|uploadpack]::
-       Do not include refs that would be hidden by `git-receive-pack` or
-       `git-upload-pack` by consulting the appropriate `receive.hideRefs` or
-       `uploadpack.hideRefs` configuration along with `transfer.hideRefs` (see
+--exclude-hidden=[fetch|receive|uploadpack]::
+       Do not include refs that would be hidden by `git-fetch`,
+       `git-receive-pack` or `git-upload-pack` by consulting the appropriate
+       `fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
+       configuration along with `transfer.hideRefs` (see
        linkgit:git-config[1]). This option affects the next pseudo-ref option
        `--all` or `--glob` and is cleared after processing them.
 
index 765b2df8530d1fc3426b75cb266b2f2213278d19..492a82323dab8e144e96897a78e1daf22c76be6e 100644 (file)
@@ -93,7 +93,7 @@ See the CONFIGURATION section for `sendemail.multiEdit`.
 
 --in-reply-to=<identifier>::
        Make the first mail (or all the mails with `--no-thread`) appear as a
-       reply to the given Message-Id, which avoids breaking threads to
+       reply to the given Message-ID, which avoids breaking threads to
        provide a new patch series.
        The second and subsequent emails will be sent as replies according to
        the `--[no-]chain-reply-to` setting.
@@ -320,6 +320,17 @@ Automating
        Output of this command must be single email address per line.
        Default is the value of `sendemail.ccCmd` configuration value.
 
+--header-cmd=<command>::
+       Specify a command that is executed once per outgoing message
+       and output RFC 2822 style header lines to be inserted into
+       them. When the `sendemail.headerCmd` configuration variable is
+       set, its value is always used. When --header-cmd is provided
+       at the command line, its value takes precedence over the
+       `sendemail.headerCmd` configuration variable.
+
+--no-header-cmd::
+       Disable any header command in use.
+
 --[no-]chain-reply-to::
        If this is set, each email will be sent as a reply to the previous
        email sent.  If disabled with "--no-chain-reply-to", all emails after
@@ -484,14 +495,10 @@ edit ~/.gitconfig to specify your account settings:
        smtpServerPort = 587
 ----
 
-If you have multi-factor authentication set up on your Gmail account, you will
-need to generate an app-specific password for use with 'git send-email'. Visit
+If you have multi-factor authentication set up on your Gmail account, you can
+generate an app-specific password for use with 'git send-email'. Visit
 https://security.google.com/settings/security/apppasswords to create it.
 
-If you do not have multi-factor authentication set up on your Gmail account,
-you will need to allow less secure app access. Visit
-https://myaccount.google.com/lesssecureapps to enable it.
-
 Once your commits are ready to be sent to the mailing list, run the
 following commands:
 
index 71f608b1ff1e1de10708212bcd815b744f9284bf..58cf6210cde2d3d1889d9fc9ac1b49bafaaa09e2 100644 (file)
@@ -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.
@@ -132,10 +131,11 @@ 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.
+
+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, one-line log for each commit is
 displayed, indented N places.  If a commit is on the I-th
index d1d56f68b4376279534d61ec44db10e9e6efd297..2fe274b8faa6d304bb27a7bc2bb9b09810a94217 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
@@ -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 68392d2a56ed045a914b1d712f694929a1842242..529a8edd9c1ed88c8b0ab9c39ab95dccd97671b3 100644 (file)
@@ -9,7 +9,7 @@ git-sparse-checkout - Reduce your working tree to a subset of tracked files
 SYNOPSIS
 --------
 [verse]
-'git sparse-checkout' (init | list | set | add | reapply | disable) [<options>]
+'git sparse-checkout' (init | list | set | add | reapply | disable | check-rules) [<options>]
 
 
 DESCRIPTION
@@ -135,6 +135,29 @@ paths to pass to a subsequent 'set' or 'add' command.  However,
 the disable command, so the easy restore of calling a plain `init`
 decreased in utility.
 
+'check-rules'::
+       Check whether sparsity rules match one or more paths.
++
+By default `check-rules` reads a list of paths from stdin and outputs only
+the ones that match the current sparsity rules. The input is expected to consist
+of one path per line, matching the output of `git ls-tree --name-only` including
+that pathnames that begin with a double quote (") are interpreted as C-style
+quoted strings.
++
+When called with the `--rules-file <file>` flag the input files are matched
+against the sparse checkout rules found in `<file>` instead of the current ones.
+The rules in the files are expected to be in the same form as accepted by `git
+sparse-checkout set --stdin` (in particular, they must be newline-delimited).
++
+By default, the rules passed to the `--rules-file` option are interpreted as
+cone mode directories. To pass non-cone mode patterns with `--rules-file`,
+combine the option with the `--no-cone` option.
++
+When called with the `-z` flag, the format of the paths input on stdin as well
+as the output paths are \0 terminated and not quoted. Note that this does not
+apply to the format of the rules passed with the `--rules-file` option.
+
+
 EXAMPLES
 --------
 `git sparse-checkout set MY/DIR1 SUB/DIR2`::
@@ -263,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 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 fdc72b5875a343aa9a0360e57bbdac684deee894..d42efb3112787f943559723b9b19915df8181d5e 100644 (file)
@@ -131,6 +131,10 @@ options for details.
 --ignore-case::
        Sorting and filtering tags are case insensitive.
 
+--omit-empty::
+       Do not print a newline after formatted refs where the format expands
+       to the empty string.
+
 --column[=<options>]::
 --no-column::
        Display tag listing in columns. See configuration variable
@@ -377,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 f40202b8e3ab521ea22c78986d3bf5bb44a67f09..c38fb3968bcabc6215f535ec569e3f5e258aee62 100644 (file)
@@ -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 063d6eeb99dd34c4b08f3c3dde9340146ce48756..a4fbf5e8386d7d4ae58230b17b534a90461ff421 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
index 74973d3cc4044d807ee2f98b0013f6811ae4f65b..11228956cd5ec400b498d7483b8a4f71ec433ab2 100644 (file)
@@ -212,6 +212,11 @@ If you just want to run git as if it was started in `<path>` then use
        nohelpers (exclude helper commands), alias and config
        (retrieve command list from config variable completion.commands)
 
+--attr-source=<tree-ish>::
+       Read gitattributes from <tree-ish> instead of the worktree. See
+       linkgit:gitattributes[5]. This is equivalent to setting the
+       `GIT_ATTR_SOURCE` environment variable.
+
 GIT COMMANDS
 ------------
 
@@ -546,10 +551,10 @@ double-quotes and respecting backslash escapes. E.g., the value
 
 `GIT_DEFAULT_HASH`::
        If this variable is set, the default hash algorithm for new
-       repositories will be set to this value. This value is currently
-       ignored when cloning; the setting of the remote repository
-       is used instead. The default is "sha1". THIS VARIABLE IS
-       EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
+       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".
+       See `--object-format` in linkgit:git-init[1].
 
 Git Commits
 ~~~~~~~~~~~
@@ -686,6 +691,9 @@ for further details.
        tells Git not to verify the SSL certificate when fetching or
        pushing over HTTPS.
 
+`GIT_ATTR_SOURCE`::
+       Sets the treeish that gitattributes will be read from.
+
 `GIT_ASKPASS`::
        If this environment variable is set, then Git commands which need to
        acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)
index 39bfbca1ffe565f52b9536beaf040539ab7c0bbc..6deb89a2967708dfc2c560ac72c29907a5b6334a 100644 (file)
@@ -120,20 +120,19 @@ repository upon 'git add' and 'git commit'.
 `text`
 ^^^^^^
 
-This attribute enables and controls end-of-line normalization.  When a
-text file is normalized, its line endings are converted to LF in the
-repository.  To control what line ending style is used in the working
-directory, use the `eol` attribute for a single file and the
-`core.eol` configuration variable for all text files.
-Note that setting `core.autocrlf` to `true` or `input` overrides
-`core.eol` (see the definitions of those options in
-linkgit:git-config[1]).
+This attribute marks the path as a text file, which enables end-of-line
+conversion: When a matching file is added to the index, the file's line
+endings are normalized to LF in the index.  Conversely, when the file is
+copied from the index to the working directory, its line endings may be
+converted from LF to CRLF depending on the `eol` attribute, the Git
+config, and the platform (see explanation of `eol` below).
 
 Set::
 
        Setting the `text` attribute on a path enables end-of-line
-       normalization and marks the path as a text file.  End-of-line
-       conversion takes place without guessing the content type.
+       conversion on checkin and checkout as described above.  Line endings
+       are normalized to LF in the index every time the file is checked in,
+       even if the file was previously added to Git with CRLF line endings.
 
 Unset::
 
@@ -142,10 +141,11 @@ Unset::
 
 Set to string value "auto"::
 
-       When `text` is set to "auto", the path is marked for automatic
-       end-of-line conversion.  If Git decides that the content is
-       text, its line endings are converted to LF on checkin.
-       When the file has been committed with CRLF, no conversion is done.
+       When `text` is set to "auto", Git decides by itself whether the file
+       is text or binary.  If it is text and the file was not already in
+       Git with CRLF endings, line endings are converted on checkin and
+       checkout as described above.  Otherwise, no conversion is done on
+       checkin or checkout.
 
 Unspecified::
 
@@ -159,26 +159,29 @@ unspecified.
 `eol`
 ^^^^^
 
-This attribute sets a specific line-ending style to be used in the
-working directory.  This attribute has effect only if the `text`
-attribute is set or unspecified, or if it is set to `auto`, the file is
-detected as text, and it is stored with LF endings in the index.  Note
-that setting this attribute on paths which are in the index with CRLF
-line endings may make the paths to be considered dirty unless
-`text=auto` is set. Adding the path to the index again will normalize
-the line endings in the index.
+This attribute marks a path to use a specific line-ending style in the
+working tree when it is checked out.  It has effect only if `text` or
+`text=auto` is set (see above), but specifying `eol` automatically sets
+`text` if `text` was left unspecified.
 
 Set to string value "crlf"::
 
-       This setting forces Git to normalize line endings for this
-       file on checkin and convert them to CRLF when the file is
-       checked out.
+       This setting converts the file's line endings in the working
+       directory to CRLF when the file is checked out.
 
 Set to string value "lf"::
 
-       This setting forces Git to normalize line endings to LF on
-       checkin and prevents conversion to CRLF when the file is
-       checked out.
+       This setting uses the same line endings in the working directory as
+       in the index when the file is checked out.
+
+Unspecified::
+
+       If the `eol` attribute is unspecified for a file, its line endings
+       in the working directory are determined by the `core.autocrlf` or
+       `core.eol` configuration variable (see the definitions of those
+       options in linkgit:git-config[1]).  If `text` is set but neither of
+       those variables is, the default is `eol=crlf` on Windows and
+       `eol=lf` on all other platforms.
 
 Backwards compatibility with `crlf` attribute
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1129,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
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 e06af02f211e7a7a8488d1470d7f76dd58e5989c..0c1be2dbe85caf3300a314c374dd12d54b7434a7 100644 (file)
@@ -611,8 +611,8 @@ result of repeatedly resetting the objects' mtimes to the present time.
 
 If you are GC-ing repositories in a mixed version environment, consider omitting
 the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
-leaving the `gc.cruftPacks` configuration unset until all writers understand
-cruft packs.
+setting the `gc.cruftPacks` configuration to "false" until all writers
+understand cruft packs.
 
 === Alternatives
 
index 62908602e7bee3ff4bd6c0aaeca39f5ac3bc7741..86f804720ae71fc3d0db94623663539bd05a06f2 100644 (file)
@@ -595,10 +595,51 @@ processed by rebase.
 sendemail-validate
 ~~~~~~~~~~~~~~~~~~
 
-This hook is invoked by linkgit:git-send-email[1].  It takes a single parameter,
-the name of the file that holds the e-mail to be sent.  Exiting with a
-non-zero status causes `git send-email` to abort before sending any
-e-mails.
+This hook is invoked by linkgit:git-send-email[1].
+
+It takes these command line arguments. They are,
+1. the name of the file which holds the contents of the email to be sent.
+2. The name of the file which holds the SMTP headers of the email.
+
+The SMTP headers are passed in the exact same way as they are passed to the
+user's Mail Transport Agent (MTA). In effect, the email given to the user's
+MTA, is the contents of $2 followed by the contents of $1.
+
+An example of a few common headers is shown below. Take notice of the
+capitalization and multi-line tab structure.
+
+  From: Example <from@example.com>
+  To: to@example.com
+  Cc: cc@example.com,
+         A <author@example.com>,
+         One <one@example.com>,
+         two@example.com
+  Subject: PATCH-STRING
+
+Exiting with a non-zero status causes `git send-email` to abort
+before sending any e-mails.
+
+The following environment variables are set when executing the hook.
+
+`GIT_SENDEMAIL_FILE_COUNTER`::
+       A 1-based counter incremented by one for every file holding an e-mail
+       to be sent (excluding any FIFOs). This counter does not follow the
+       patch series counter scheme. It will always start at 1 and will end at
+       GIT_SENDEMAIL_FILE_TOTAL.
+
+`GIT_SENDEMAIL_FILE_TOTAL`::
+       The total number of files that will be sent (excluding any FIFOs). This
+       counter does not follow the patch series counter scheme. It will always
+       be equal to the number of files being sent, whether there is a cover
+       letter or not.
+
+These variables may for instance be used to validate patch series.
+
+The sample `sendemail-validate` hook that comes with Git checks that all sent
+patches (excluding the cover letter) can be applied on top of the upstream
+repository default branch without conflicts. Some placeholders are left for
+additional validation steps to be performed after all patches of a given series
+have been applied.
 
 fsmonitor-watchman
 ~~~~~~~~~~~~~~~~~~
index f2738b10db6b2be5e7babb74fbe013faecd425d1..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
@@ -146,7 +146,9 @@ The purpose of gitignore files is to ensure that certain files
 not tracked by Git remain untracked.
 
 To stop tracking a file that is currently tracked, use
-'git rm --cached'.
+'git rm --cached' to remove the file from the index. The filename
+can then be added to the `.gitignore` file to stop the file from
+being reintroduced in later commits.
 
 Git does not follow symbolic links when accessing a `.gitignore` file in
 the working tree. This keeps behavior consistent when the file is
@@ -172,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 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 0e0b863105b104b706d3cc75b4d3998a4abe580f..c7cadd8aaf1a0e6606d2b559b674526bc687849a 100644 (file)
@@ -49,7 +49,7 @@ $ git config --global user.email you@yourdomain.example.com
 Importing a new project
 -----------------------
 
-Assume you have a tarball project.tar.gz with your initial work.  You
+Assume you have a tarball `project.tar.gz` with your initial work.  You
 can place it under Git revision control as follows.
 
 ------------------------------------------------
@@ -65,10 +65,10 @@ Initialized empty Git repository in .git/
 ------------------------------------------------
 
 You've now initialized the working directory--you may notice a new
-directory created, named ".git".
+directory created, named `.git`.
 
 Next, tell Git to take a snapshot of the contents of all files under the
-current directory (note the '.'), with 'git add':
+current directory (note the `.`), with `git add`:
 
 ------------------------------------------------
 $ git add .
@@ -76,7 +76,7 @@ $ git add .
 
 This snapshot is now stored in a temporary staging area which Git calls
 the "index".  You can permanently store the contents of the index in the
-repository with 'git commit':
+repository with `git commit`:
 
 ------------------------------------------------
 $ git commit
@@ -95,21 +95,20 @@ $ git add file1 file2 file3
 ------------------------------------------------
 
 You are now ready to commit.  You can see what is about to be committed
-using 'git diff' with the --cached option:
+using `git diff` with the `--cached` option:
 
 ------------------------------------------------
 $ git diff --cached
 ------------------------------------------------
 
-(Without --cached, 'git diff' will show you any changes that
+(Without `--cached`, `git diff` will show you any changes that
 you've made but not yet added to the index.)  You can also get a brief
-summary of the situation with 'git status':
+summary of the situation with `git status`:
 
 ------------------------------------------------
 $ git status
 On branch master
 Changes to be committed:
-Your branch is up to date with 'origin/master'.
   (use "git restore --staged <file>..." to unstage)
 
        modified:   file1
@@ -128,7 +127,7 @@ $ git commit
 This will again prompt you for a message describing the change, and then
 record a new version of the project.
 
-Alternatively, instead of running 'git add' beforehand, you can use
+Alternatively, instead of running `git add` beforehand, you can use
 
 ------------------------------------------------
 $ git commit -a
@@ -151,7 +150,7 @@ Git tracks content not files
 
 Many revision control systems provide an `add` command that tells the
 system to start tracking changes to a new file.  Git's `add` command
-does something simpler and more powerful: 'git add' is used both for new
+does something simpler and more powerful: `git add` is used both for new
 and newly modified files, and in both cases it takes a snapshot of the
 given files and stages that content in the index, ready for inclusion in
 the next commit.
@@ -182,7 +181,7 @@ Managing branches
 -----------------
 
 A single Git repository can maintain multiple branches of
-development.  To create a new branch named "experimental", use
+development.  To create a new branch named `experimental`, use
 
 ------------------------------------------------
 $ git branch experimental
@@ -201,8 +200,8 @@ you'll get a list of all existing branches:
 * master
 ------------------------------------------------
 
-The "experimental" branch is the one you just created, and the
-"master" branch is a default branch that was created for you
+The `experimental` branch is the one you just created, and the
+`master` branch is a default branch that was created for you
 automatically.  The asterisk marks the branch you are currently on;
 type
 
@@ -210,8 +209,8 @@ type
 $ git switch experimental
 ------------------------------------------------
 
-to switch to the experimental branch.  Now edit a file, commit the
-change, and switch back to the master branch:
+to switch to the `experimental` branch.  Now edit a file, commit the
+change, and switch back to the `master` branch:
 
 ------------------------------------------------
 (edit file)
@@ -220,9 +219,9 @@ $ git switch master
 ------------------------------------------------
 
 Check that the change you made is no longer visible, since it was
-made on the experimental branch and you're back on the master branch.
+made on the `experimental` branch and you're back on the `master` branch.
 
-You can make a different change on the master branch:
+You can make a different change on the `master` branch:
 
 ------------------------------------------------
 (edit file)
@@ -230,7 +229,7 @@ $ git commit -a
 ------------------------------------------------
 
 at this point the two branches have diverged, with different changes
-made in each.  To merge the changes made in experimental into master, run
+made in each.  To merge the changes made in `experimental` into `master`, run
 
 ------------------------------------------------
 $ git merge experimental
@@ -258,16 +257,16 @@ $ gitk
 
 will show a nice graphical representation of the resulting history.
 
-At this point you could delete the experimental branch with
+At this point you could delete the `experimental` branch with
 
 ------------------------------------------------
 $ git branch -d experimental
 ------------------------------------------------
 
-This command ensures that the changes in the experimental branch are
+This command ensures that the changes in the `experimental` branch are
 already in the current branch.
 
-If you develop on a branch crazy-idea, then regret it, you can always
+If you develop on a branch `crazy-idea`, then regret it, you can always
 delete the branch with
 
 -------------------------------------
@@ -281,7 +280,7 @@ Using Git for collaboration
 ---------------------------
 
 Suppose that Alice has started a new project with a Git repository in
-/home/alice/project, and that Bob, who has a home directory on the
+`/home/alice/project`, and that Bob, who has a home directory on the
 same machine, wants to contribute.
 
 Bob begins with:
@@ -290,7 +289,7 @@ Bob begins with:
 bob$ git clone /home/alice/project myrepo
 ------------------------------------------------
 
-This creates a new directory "myrepo" containing a clone of Alice's
+This creates a new directory `myrepo` containing a clone of Alice's
 repository.  The clone is on an equal footing with the original
 project, possessing its own copy of the original project's history.
 
@@ -303,31 +302,31 @@ bob$ git commit -a
 ------------------------------------------------
 
 When he's ready, he tells Alice to pull changes from the repository
-at /home/bob/myrepo.  She does this with:
+at `/home/bob/myrepo`.  She does this with:
 
 ------------------------------------------------
 alice$ cd /home/alice/project
 alice$ git pull /home/bob/myrepo master
 ------------------------------------------------
 
-This merges the changes from Bob's "master" branch into Alice's
+This merges the changes from Bob's `master` branch into Alice's
 current branch.  If Alice has made her own changes in the meantime,
 then she may need to manually fix any conflicts.
 
-The "pull" command thus performs two operations: it fetches changes
+The `pull` command thus performs two operations: it fetches changes
 from a remote branch, then merges them into the current branch.
 
 Note that in general, Alice would want her local changes committed before
-initiating this "pull".  If Bob's work conflicts with what Alice did since
+initiating this `pull`.  If Bob's work conflicts with what Alice did since
 their histories forked, Alice will use her working tree and the index to
 resolve conflicts, and existing local changes will interfere with the
 conflict resolution process (Git will still perform the fetch but will
 refuse to merge -- Alice will have to get rid of her local changes in
 some way and pull again when this happens).
 
-Alice can peek at what Bob did without merging first, using the "fetch"
+Alice can peek at what Bob did without merging first, using the `fetch`
 command; this allows Alice to inspect what Bob did, using a special
-symbol "FETCH_HEAD", in order to determine if he has anything worth
+symbol `FETCH_HEAD`, in order to determine if he has anything worth
 pulling, like this:
 
 ------------------------------------------------
@@ -336,10 +335,10 @@ alice$ git log -p HEAD..FETCH_HEAD
 ------------------------------------------------
 
 This operation is safe even if Alice has uncommitted local changes.
-The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable
-from the FETCH_HEAD but exclude anything that is reachable from HEAD".
-Alice already knows everything that leads to her current state (HEAD),
-and reviews what Bob has in his state (FETCH_HEAD) that she has not
+The range notation `HEAD..FETCH_HEAD` means "show everything that is reachable
+from the `FETCH_HEAD` but exclude anything that is reachable from `HEAD`".
+Alice already knows everything that leads to her current state (`HEAD`),
+and reviews what Bob has in his state (`FETCH_HEAD`) that she has not
 seen with this command.
 
 If Alice wants to visualize what Bob did since their histories forked
@@ -349,7 +348,7 @@ she can issue the following command:
 $ gitk HEAD..FETCH_HEAD
 ------------------------------------------------
 
-This uses the same two-dot range notation we saw earlier with 'git log'.
+This uses the same two-dot range notation we saw earlier with `git log`.
 
 Alice may want to view what both of them did since they forked.
 She can use three-dot form instead of the two-dot form:
@@ -361,13 +360,13 @@ $ gitk HEAD...FETCH_HEAD
 This means "show everything that is reachable from either one, but
 exclude anything that is reachable from both of them".
 
-Please note that these range notation can be used with both gitk
-and "git log".
+Please note that these range notation can be used with both `gitk`
+and `git log`.
 
 After inspecting what Bob did, if there is nothing urgent, Alice may
 decide to continue working without pulling from Bob.  If Bob's history
 does have something Alice would immediately need, Alice may choose to
-stash her work-in-progress first, do a "pull", and then finally unstash
+stash her work-in-progress first, do a `pull`, and then finally unstash
 her work-in-progress on top of the resulting history.
 
 When you are working in a small closely knit group, it is not
@@ -379,8 +378,8 @@ it easier:
 alice$ git remote add bob /home/bob/myrepo
 ------------------------------------------------
 
-With this, Alice can perform the first part of the "pull" operation
-alone using the 'git fetch' command without merging them with her own
+With this, Alice can perform the first part of the `pull` operation
+alone using the `git fetch` command without merging them with her own
 branch, using:
 
 -------------------------------------
@@ -388,7 +387,7 @@ alice$ git fetch bob
 -------------------------------------
 
 Unlike the longhand form, when Alice fetches from Bob using a
-remote repository shorthand set up with 'git remote', what was
+remote repository shorthand set up with `git remote`, what was
 fetched is stored in a remote-tracking branch, in this case
 `bob/master`.  So after this:
 
@@ -397,10 +396,10 @@ alice$ git log -p master..bob/master
 -------------------------------------
 
 shows a list of all the changes that Bob made since he branched from
-Alice's master branch.
+Alice's `master` branch.
 
 After examining those changes, Alice
-could merge the changes into her master branch:
+could merge the changes into her `master` branch:
 
 -------------------------------------
 alice$ git merge bob/master
@@ -432,12 +431,12 @@ bob$ git config --get remote.origin.url
 /home/alice/project
 -------------------------------------
 
-(The complete configuration created by 'git clone' is visible using
+(The complete configuration created by `git clone` is visible using
 `git config -l`, and the linkgit:git-config[1] man page
 explains the meaning of each option.)
 
-Git also keeps a pristine copy of Alice's master branch under the
-name "origin/master":
+Git also keeps a pristine copy of Alice's `master` branch under the
+name `origin/master`:
 
 -------------------------------------
 bob$ git branch -r
@@ -462,8 +461,8 @@ Exploring history
 -----------------
 
 Git history is represented as a series of interrelated commits.  We
-have already seen that the 'git log' command can list those commits.
-Note that first line of each git log entry also gives a name for the
+have already seen that the `git log` command can list those commits.
+Note that first line of each `git log` entry also gives a name for the
 commit:
 
 -------------------------------------
@@ -475,7 +474,7 @@ Date:   Tue May 16 17:18:22 2006 -0700
     merge-base: Clarify the comments on post processing.
 -------------------------------------
 
-We can give this name to 'git show' to see the details about this
+We can give this name to `git show` to see the details about this
 commit.
 
 -------------------------------------
@@ -514,7 +513,7 @@ You can also give commits names of your own; after running
 $ git tag v2.5 1b2e1d63ff
 -------------------------------------
 
-you can refer to 1b2e1d63ff by the name "v2.5".  If you intend to
+you can refer to `1b2e1d63ff` by the name `v2.5`.  If you intend to
 share this name with other people (for example, to identify a release
 version), you should create a "tag" object, and perhaps sign it; see
 linkgit:git-tag[1] for details.
@@ -533,22 +532,22 @@ $ git reset --hard HEAD^ # reset your current branch and working
 Be careful with that last command: in addition to losing any changes
 in the working directory, it will also remove all later commits from
 this branch.  If this branch is the only branch containing those
-commits, they will be lost.  Also, don't use 'git reset' on a
+commits, they will be lost.  Also, don't use `git reset` on a
 publicly-visible branch that other developers pull from, as it will
 force needless merges on other developers to clean up the history.
-If you need to undo changes that you have pushed, use 'git revert'
+If you need to undo changes that you have pushed, use `git revert`
 instead.
 
-The 'git grep' command can search for strings in any version of your
+The `git grep` command can search for strings in any version of your
 project, so
 
 -------------------------------------
 $ git grep "hello" v2.5
 -------------------------------------
 
-searches for all occurrences of "hello" in v2.5.
+searches for all occurrences of "hello" in `v2.5`.
 
-If you leave out the commit name, 'git grep' will search any of the
+If you leave out the commit name, `git grep` will search any of the
 files it manages in your current directory.  So
 
 -------------------------------------
@@ -558,7 +557,7 @@ $ git grep "hello"
 is a quick way to search just the files that are tracked by Git.
 
 Many Git commands also take sets of commits, which can be specified
-in a number of ways.  Here are some examples with 'git log':
+in a number of ways.  Here are some examples with `git log`:
 
 -------------------------------------
 $ git log v2.5..v2.6            # commits between v2.5 and v2.6
@@ -568,16 +567,16 @@ $ git log v2.5.. Makefile       # commits since v2.5 which modify
                                # Makefile
 -------------------------------------
 
-You can also give 'git log' a "range" of commits where the first is not
+You can also give `git log` a "range" of commits where the first is not
 necessarily an ancestor of the second; for example, if the tips of
-the branches "stable" and "master" diverged from a common
+the branches `stable` and `master` diverged from a common
 commit some time ago, then
 
 -------------------------------------
 $ git log stable..master
 -------------------------------------
 
-will list commits made in the master branch but not in the
+will list commits made in the `master` branch but not in the
 stable branch, while
 
 -------------------------------------
@@ -585,15 +584,15 @@ $ git log master..stable
 -------------------------------------
 
 will show the list of commits made on the stable branch but not
-the master branch.
+the `master` branch.
 
-The 'git log' command has a weakness: it must present commits in a
+The `git log` command has a weakness: it must present commits in a
 list.  When the history has lines of development that diverged and
-then merged back together, the order in which 'git log' presents
+then merged back together, the order in which `git log` presents
 those commits is meaningless.
 
 Most projects with multiple contributors (such as the Linux kernel,
-or Git itself) have frequent merges, and 'gitk' does a better job of
+or Git itself) have frequent merges, and `gitk` does a better job of
 visualizing their history.  For example,
 
 -------------------------------------
@@ -601,7 +600,7 @@ $ gitk --since="2 weeks ago" drivers/
 -------------------------------------
 
 allows you to browse any commits from the last 2 weeks of commits
-that modified files under the "drivers" directory.  (Note: you can
+that modified files under the `drivers` directory.  (Note: you can
 adjust gitk's fonts by holding down the control key while pressing
 "-" or "+".)
 
@@ -613,7 +612,7 @@ of the file:
 $ git diff v2.5:Makefile HEAD:Makefile.in
 -------------------------------------
 
-You can also use 'git show' to see any such file:
+You can also use `git show` to see any such file:
 
 -------------------------------------
 $ git show v2.5:Makefile
@@ -649,7 +648,7 @@ digressions that may be interesting at this point are:
 
   * linkgit:git-bisect[1]: When there is a regression in your
     project, one way to track down the bug is by searching through
-    the history to find the exact commit that's to blame.  Git bisect
+    the history to find the exact commit that's to blame.  `git bisect`
     can help you perform a binary search for that commit.  It is
     smart enough to perform a close-to-optimal search even in the
     case of complex non-linear history with lots of merged branches.
index 7cee9d36899101b1ea48cebcb875388164b002b8..af6bf3c45ec1b78c13a0886c2824eb980099c706 100644 (file)
@@ -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.
 
diff --git a/Documentation/manpage-base-url.xsl.in b/Documentation/manpage-base-url.xsl.in
deleted file mode 100644 (file)
index e800904..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<!-- manpage-base-url.xsl:
-     special settings for manpages rendered from newer docbook -->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-               version="1.0">
-
-<!-- set a base URL for relative links -->
-<xsl:param name="man.base.url.for.relative.links"
-       >@@MAN_BASE_URL@@</xsl:param>
-
-</xsl:stylesheet>
index a9c7ec69f46d8c631e86449aafdf327d8e51d435..beb5ff8ec2bbc271cb61f52929d3286c027a864a 100644 (file)
@@ -8,19 +8,7 @@
 <xsl:param name="man.output.quietly" select="1"/>
 <xsl:param name="refentry.meta.get.quietly" select="1"/>
 
-<!-- convert asciidoc callouts to man page format -->
-<xsl:template match="co">
-       <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/>
-</xsl:template>
-<xsl:template match="calloutlist">
-       <xsl:text>.sp&#10;</xsl:text>
-       <xsl:apply-templates/>
-       <xsl:text>&#10;</xsl:text>
-</xsl:template>
-<xsl:template match="callout">
-       <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/>
-       <xsl:apply-templates/>
-       <xsl:text>.br&#10;</xsl:text>
-</xsl:template>
+<!-- unset maximum length of title -->
+<xsl:param name="man.th.title.max.length"/>
 
 </xsl:stylesheet>
diff --git a/Documentation/manpage-quote-apos.xsl b/Documentation/manpage-quote-apos.xsl
deleted file mode 100644 (file)
index aeb8839..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-               version="1.0">
-
-<!-- work around newer groff/man setups using a prettier apostrophe
-     that unfortunately does not quote anything when cut&pasting
-     examples to the shell -->
-<xsl:template name="escape.apostrophe">
-  <xsl:param name="content"/>
-  <xsl:call-template name="string.subst">
-    <xsl:with-param name="string" select="$content"/>
-    <xsl:with-param name="target">'</xsl:with-param>
-    <xsl:with-param name="replacement">\(aq</xsl:with-param>
-  </xsl:call-template>
-</xsl:template>
-
-</xsl:stylesheet>
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 0d90d5b1549aa2e50647e1a0a6195a2ed301d699..a4a0cb93b241b8d5d9c9bc9b200a277a0e4f7992 100644 (file)
@@ -195,10 +195,11 @@ respectively, and they must begin with `refs/` when applied to `--glob`
 or `--all`. If a trailing '/{asterisk}' is intended, it must be given
 explicitly.
 
---exclude-hidden=[receive|uploadpack]::
-       Do not include refs that would be hidden by `git-receive-pack` or
-       `git-upload-pack` by consulting the appropriate `receive.hideRefs` or
-       `uploadpack.hideRefs` configuration along with `transfer.hideRefs` (see
+--exclude-hidden=[fetch|receive|uploadpack]::
+       Do not include refs that would be hidden by `git-fetch`,
+       `git-receive-pack` or `git-upload-pack` by consulting the appropriate
+       `fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
+       configuration along with `transfer.hideRefs` (see
        linkgit:git-config[1]). This option affects the next pseudo-ref option
        `--all` or `--glob` and is cleared after processing them.
 
@@ -235,10 +236,11 @@ 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.
 
 ifdef::git-rev-list[]
 --quiet::
@@ -889,7 +891,7 @@ ifdef::git-rev-list[]
        Print the object IDs of any object referenced by the listed
        commits.  `--objects foo ^bar` thus means ``send me
        all object IDs which I need to download if I have the commit
-       object _bar_ but not _foo_''.
+       object _bar_ but not _foo_''. See also `--object-names` below.
 
 --in-commit-order::
        Print tree and blob ids in order of the commits. The tree
@@ -919,7 +921,12 @@ ifdef::git-rev-list[]
 
 --object-names::
        Only useful with `--objects`; print the names of the object IDs
-       that are found. This is the default behavior.
+       that are found. This is the default behavior. Note that the
+       "name" of each object is ambiguous, and mostly intended as a
+       hint for packing objects. In particular: no distinction is made between
+       the names of tags, trees, and blobs; path names may be modified
+       to remove newlines; and if an object would appear multiple times
+       with different names, only one name is shown.
 
 --no-object-names::
        Only useful with `--objects`; does not print the names of the object
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 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 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 e410912fe52b9defd6de1601174cd214998ab336..ae8c2db427bb6a5671b6cf598574e8392c715d97 100644 (file)
@@ -35,7 +35,7 @@ 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
 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`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index dc9c6a663a97e644d865e7d01957bfa2ac77bb5d..4281396093d7c92d22ccf2a8f7dd7c98400445e2 100644 (file)
@@ -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 71425bd821f6a96e501c05e8868adc566f92de3e..2c8dae398f661b349ebec3734fba135a81cbd67b 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.40.1
+DEF_VER=v2.42.0
 
 LF='
 '
index 50ee51fde3208db679e118338b364efc72658fe1..5776309365357a5848c5f03214690e75d7deb57c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -207,10 +207,6 @@ include shared.mak
 # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
 # field that counts the on-disk footprint in 512-byte blocks.
 #
-# Define GNU_ROFF if your target system uses GNU groff.  This forces
-# apostrophes to be ASCII so that cut&pasting examples to the shell
-# will work.
-#
 # Define USE_ASCIIDOCTOR to use Asciidoctor instead of AsciiDoc to build the
 # documentation.
 #
@@ -1036,6 +1032,7 @@ LIB_OBJS += fsmonitor.o
 LIB_OBJS += fsmonitor-ipc.o
 LIB_OBJS += fsmonitor-settings.o
 LIB_OBJS += gettext.o
+LIB_OBJS += git-zlib.o
 LIB_OBJS += gpg-interface.o
 LIB_OBJS += graph.o
 LIB_OBJS += grep.o
@@ -1054,7 +1051,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
@@ -1063,6 +1059,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
@@ -1145,6 +1142,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
@@ -1196,7 +1194,6 @@ LIB_OBJS += write-or-die.o
 LIB_OBJS += ws.o
 LIB_OBJS += wt-status.o
 LIB_OBJS += xdiff-interface.o
-LIB_OBJS += zlib.o
 
 BUILTIN_OBJS += builtin/add.o
 BUILTIN_OBJS += builtin/am.o
@@ -1955,7 +1952,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
@@ -2746,8 +2743,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
@@ -2782,6 +2779,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)
 
@@ -3219,6 +3223,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
@@ -3655,6 +3665,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)
@@ -3683,6 +3694,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 829f78a6ebb6a9d1e89bdcae22c57b61346d0b1e..0527f30c2d8ff1c8bda66ddbddff0ff436ad0813 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.40.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.42.0.txt
\ No newline at end of file
index 39e06b58486e3e94e640929c27460e786533a2f8..1202cde23dbc9b27e3bee5d3198a9cec3236a288 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "strbuf.h"
 
 /*
  * Do not use this for inspecting *tracked* content.  When path is a
@@ -280,3 +282,46 @@ char *prefix_filename(const char *pfx, const char *arg)
 #endif
        return strbuf_detach(&path, NULL);
 }
+
+char *prefix_filename_except_for_dash(const char *pfx, const char *arg)
+{
+       if (!strcmp(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);
+}
diff --git a/abspath.h b/abspath.h
new file mode 100644 (file)
index 0000000..4653080
--- /dev/null
+++ b/abspath.h
@@ -0,0 +1,54 @@
+#ifndef ABSPATH_H
+#define ABSPATH_H
+
+int is_directory(const char *);
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+                     int die_on_error);
+char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
+                               int die_on_error);
+char *real_pathdup(const char *path, int die_on_error);
+const char *absolute_path(const char *path);
+char *absolute_pathdup(const char *path);
+
+/*
+ * Concatenate "prefix" (if len is non-zero) and "path", with no
+ * connecting characters (so "prefix" should end with a "/").
+ * Unlike prefix_path, this should be used if the named file does
+ * not have to interact with index entry; i.e. name of a random file
+ * on the filesystem.
+ *
+ * The return value is always a newly allocated string (even if the
+ * prefix was empty).
+ */
+char *prefix_filename(const char *prefix, const char *path);
+
+/* Likewise, but path=="-" always yields "-" */
+char *prefix_filename_except_for_dash(const char *prefix, const char *path);
+
+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 00a0f6f96f3f5ebc54bbfb841921c5ceff88c1c3..7fd00c5e2502d6aa2c151196f87fb20ed0c0c578 100644 (file)
@@ -1,8 +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"
@@ -10,6 +16,7 @@
 #include "dir.h"
 #include "run-command.h"
 #include "prompt.h"
+#include "tree.h"
 
 static void init_color(struct repository *r, struct add_i_state *s,
                       const char *section_and_slot, char *dst,
@@ -551,7 +558,7 @@ static int get_modified_files(struct repository *r,
                opt.def = is_initial ?
                        empty_tree_oid_hex() : oid_to_hex(&head_oid);
 
-               init_revisions(&rev, NULL);
+               repo_init_revisions(r, &rev, NULL);
                setup_revisions(0, NULL, &rev, &opt);
 
                rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
@@ -562,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);
index a86a92e16461384cbe8ac880fa6515e0f74e243c..bfe19876cd50c5aca2e465d9334c49e65a1972fc 100644 (file)
@@ -1,5 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "add-interactive.h"
+#include "advice.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"
@@ -414,7 +421,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                strvec_push(&args,
                            /* could be on an unborn branch */
                            !strcmp("HEAD", s->revision) &&
-                           get_oid("HEAD", &oid) ?
+                           repo_get_oid(the_repository, "HEAD", &oid) ?
                            empty_tree_oid_hex() : s->revision);
        }
        color_arg_index = args.nr;
@@ -483,7 +490,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                if (!eol)
                        eol = pend;
 
-               if (starts_with(p, "diff ")) {
+               if (starts_with(p, "diff ") ||
+                   starts_with(p, "* Unmerged path ")) {
                        complete_file(marker, hunk);
                        ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
                                   file_diff_alloc);
@@ -1098,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"
@@ -1110,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 fd189689437c7512e549482fe696f7a2d2400cd2..50c79443ba749fc56437806c21a20755c1988714 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "config.h"
 #include "color.h"
+#include "gettext.h"
 #include "help.h"
 #include "string-list.h"
 
@@ -44,6 +46,7 @@ static struct {
        [ADVICE_COMMIT_BEFORE_MERGE]                    = { "commitBeforeMerge", 1 },
        [ADVICE_DETACHED_HEAD]                          = { "detachedHead", 1 },
        [ADVICE_SUGGEST_DETACHING_HEAD]                 = { "suggestDetachingHead", 1 },
+       [ADVICE_DIVERGING]                              = { "diverging", 1 },
        [ADVICE_FETCH_SHOW_FORCED_UPDATES]              = { "fetchShowForcedUpdates", 1 },
        [ADVICE_GRAFT_FILE_DEPRECATED]                  = { "graftFileDeprecated", 1 },
        [ADVICE_IGNORED_HOOK]                           = { "ignoredHook", 1 },
@@ -75,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[] =
@@ -187,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))
                /*
@@ -217,6 +222,14 @@ void NORETURN die_conclude_merge(void)
 
 void NORETURN die_ff_impossible(void)
 {
+       advise_if_enabled(ADVICE_DIVERGING,
+               _("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"));
        die(_("Not possible to fast-forward, aborting."));
 }
 
index 07e0f76833e78070a26ec288db929ec966024d7e..2affbe142616de0d329c9aaaaee9ca355fb73adf 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -1,8 +1,6 @@
 #ifndef ADVICE_H
 #define ADVICE_H
 
-#include "git-compat-util.h"
-
 struct string_list;
 
 /*
@@ -21,6 +19,7 @@ struct string_list;
        ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
        ADVICE_COMMIT_BEFORE_MERGE,
        ADVICE_DETACHED_HEAD,
+       ADVICE_DIVERGING,
        ADVICE_SUGGEST_DETACHING_HEAD,
        ADVICE_FETCH_SHOW_FORCED_UPDATES,
        ADVICE_GRAFT_FILE_DEPRECATED,
@@ -50,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 00abde081739436236aa077412c3b5b686144f42..5a238f2e3012d2fb12443b27ed02831e9edee476 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "alias.h"
 #include "config.h"
+#include "gettext.h"
+#include "strbuf.h"
 #include "string-list.h"
 
 struct config_alias_data {
@@ -9,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;
@@ -44,6 +47,23 @@ void list_aliases(struct string_list *list)
        read_early_config(config_alias_cb, &data);
 }
 
+void quote_cmdline(struct strbuf *buf, const char **argv)
+{
+       for (const char **argp = argv; *argp; argp++) {
+               if (argp != argv)
+                       strbuf_addch(buf, ' ');
+               strbuf_addch(buf, '"');
+               for (const char *p = *argp; *p; p++) {
+                       const char c = *p;
+
+                       if (c == '"' || c =='\\')
+                               strbuf_addch(buf, '\\');
+                       strbuf_addch(buf, c);
+               }
+               strbuf_addch(buf, '"');
+       }
+}
+
 #define SPLIT_CMDLINE_BAD_ENDING 1
 #define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
 #define SPLIT_CMDLINE_ARGC_OVERFLOW 3
diff --git a/alias.h b/alias.h
index aef4843bb7821e87dcbe017ddfff64b8d6681fca..43db736484d1059aab35758e4162e6ade6c15539 100644 (file)
--- a/alias.h
+++ b/alias.h
@@ -1,9 +1,12 @@
 #ifndef ALIAS_H
 #define ALIAS_H
 
+struct strbuf;
 struct string_list;
 
 char *alias_lookup(const char *alias);
+/* Quote argv so buf can be parsed by split_cmdline() */
+void quote_cmdline(struct strbuf *buf, const char **argv);
 int split_cmdline(char *cmdline, const char ***argv);
 /* Takes a negative value returned by split_cmdline */
 const char *split_cmdline_strerror(int cmdline_errno);
diff --git a/alloc.c b/alloc.c
index 27f697e4c87a05ef7cc847a17e83e14e9cfd2a4d..377e80f5dda2f80e6222f4eb2fa8c607d708cc9d 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -8,11 +8,12 @@
  * up with maximal alignment because it doesn't know what the object alignment
  * for the new allocation is.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "object.h"
 #include "blob.h"
 #include "tree.h"
 #include "commit.h"
+#include "repository.h"
 #include "tag.h"
 #include "alloc.h"
 
diff --git a/apply.c b/apply.c
index 976215785d564edb8569d539be7274ea262efe39..3d69fec836d41fbae10988606ac20ce96dad562d 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -7,21 +7,35 @@
  *
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.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 "dir.h"
+#include "environment.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"
 
 struct gitdiff_data {
        struct strbuf *root;
@@ -398,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
@@ -3201,7 +3216,8 @@ static int apply_binary(struct apply_state *state,
                unsigned long size;
                char *result;
 
-               result = read_object_file(&oid, &type, &size);
+               result = repo_read_object_file(the_repository, &oid, &type,
+                                              &size);
                if (!result)
                        return error(_("the necessary postimage %s for "
                                       "'%s' cannot be read"),
@@ -3264,7 +3280,8 @@ static int read_blob_object(struct strbuf *buf, const struct object_id *oid, uns
                unsigned long sz;
                char *result;
 
-               result = read_object_file(oid, &type, &sz);
+               result = repo_read_object_file(the_repository, oid, &type,
+                                              &sz);
                if (!result)
                        return -1;
                /* XXX read_sha1_file NUL-terminates */
@@ -3492,7 +3509,8 @@ static int resolve_to(struct image *image, const struct object_id *result_id)
 
        clear_image(image);
 
-       image->buf = read_object_file(result_id, &type, &size);
+       image->buf = repo_read_object_file(the_repository, result_id, &type,
+                                          &size);
        if (!image->buf || type != OBJ_BLOB)
                die("unable to read blob object %s", oid_to_hex(result_id));
        image->len = size;
@@ -3610,7 +3628,7 @@ static int try_threeway(struct apply_state *state,
        /* Preimage the patch was prepared for */
        if (patch->is_new)
                write_object_file("", 0, OBJ_BLOB, &pre_oid);
-       else if (get_oid(patch->old_oid_prefix, &pre_oid) ||
+       else if (repo_get_oid(the_repository, patch->old_oid_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to perform 3-way merge."));
 
@@ -4127,7 +4145,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        else
                                return error(_("sha1 information is lacking or "
                                               "useless for submodule %s"), name);
-               } else if (!get_oid_blob(patch->old_oid_prefix, &oid)) {
+               } else if (!repo_get_oid_blob(the_repository, patch->old_oid_prefix, &oid)) {
                        ; /* ok */
                } else if (!patch->lines_added && !patch->lines_deleted) {
                        /* mode-only change: update the current */
diff --git a/apply.h b/apply.h
index b9f18ce87d1e0374a04aaaf785592c752dba6058..7cd38b1443c67e448bdc9f004f94a841a12eb747 100644 (file)
--- a/apply.h
+++ b/apply.h
@@ -1,7 +1,7 @@
 #ifndef APPLY_H
 #define APPLY_H
 
-#include "hash.h"
+#include "hash-ll.h"
 #include "lockfile.h"
 #include "string-list.h"
 #include "strmap.h"
index f8fad2946ef97324756b78363fb90d329f504209..07269968399a5e1b1731fb458d48f4188ed25577 100644 (file)
@@ -1,13 +1,17 @@
 /*
  * Copyright (c) 2005, 2006 Rene Scharfe
  */
-#include "cache.h"
+#include "git-compat-util.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"
 
 #define RECORDSIZE     (512)
 #define BLOCKSIZE      (RECORDSIZE * 20)
@@ -406,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 0456f1ebf15c839639f4759c329cb957b0a64feb..7229e3e454feb080509d1587a974925ff1318f31 100644 (file)
@@ -1,13 +1,17 @@
 /*
  * Copyright (c) 2006 Rene Scharfe
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "archive.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#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"
 #include "date.h"
 
@@ -613,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 9aeaf2bd87dfb884479f6e6a1b609d082ac39896..ca11db185b15a73dd31b239d91a609071faa9a2a 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -1,8 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.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"
 #include "attr.h"
 #include "archive.h"
@@ -59,7 +68,8 @@ static void format_subst(const struct commit *commit,
                strbuf_add(&fmt, b + 8, c - b - 8);
 
                strbuf_add(buf, src, b - src);
-               format_commit_message(commit, fmt.buf, buf, ctx);
+               repo_format_commit_message(the_repository, commit, fmt.buf,
+                                          buf, ctx);
                len -= c + 1 - src;
                src  = c + 1;
        }
@@ -84,7 +94,7 @@ static void *object_file_to_archive(const struct archiver_args *args,
                               (args->tree ? &args->tree->object.oid : NULL), oid);
 
        path += args->baselen;
-       buffer = read_object_file(oid, type, sizep);
+       buffer = repo_read_object_file(the_repository, oid, type, sizep);
        if (buffer && S_ISREG(mode)) {
                struct strbuf buf = STRBUF_INIT;
                size_t size = 0;
@@ -120,7 +130,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
        static struct attr_check *check;
        if (!check)
                check = attr_check_initl("export-ignore", "export-subst", NULL);
-       git_check_attr(istate, NULL, path, check);
+       git_check_attr(istate, path, check);
        return check;
 }
 
@@ -166,6 +176,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
                args->convert = check_attr_export_subst(check);
        }
 
+       if (args->prefix) {
+               static struct strbuf new_path = STRBUF_INIT;
+               static struct strbuf buf = STRBUF_INIT;
+               const char *rel;
+
+               rel = relative_path(path_without_prefix, args->prefix, &buf);
+
+               /*
+                * We don't add an entry for the current working
+                * directory when we are at the root; skip it also when
+                * we're in a subdirectory or submodule.  Skip entries
+                * higher up as well.
+                */
+               if (!strcmp(rel, "./") || starts_with(rel, "../"))
+                       return S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0;
+
+               /* rel can refer to path, so don't edit it in place */
+               strbuf_reset(&new_path);
+               strbuf_add(&new_path, args->base, args->baselen);
+               strbuf_addstr(&new_path, rel);
+               strbuf_swap(&path, &new_path);
+       }
+
        if (args->verbose)
                fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
 
@@ -401,6 +434,27 @@ static int reject_entry(const struct object_id *oid UNUSED,
        return ret;
 }
 
+static int reject_outside(const struct object_id *oid UNUSED,
+                         struct strbuf *base, const char *filename,
+                         unsigned mode, void *context)
+{
+       struct archiver_args *args = context;
+       struct strbuf buf = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       int ret = 0;
+
+       if (S_ISDIR(mode))
+               return READ_TREE_RECURSIVE;
+
+       strbuf_addbuf(&path, base);
+       strbuf_addstr(&path, filename);
+       if (starts_with(relative_path(path.buf, args->prefix, &buf), "../"))
+               ret = -1;
+       strbuf_release(&buf);
+       strbuf_release(&path);
+       return ret;
+}
+
 static int path_exists(struct archiver_args *args, const char *path)
 {
        const char *paths[] = { path, NULL };
@@ -408,8 +462,13 @@ static int path_exists(struct archiver_args *args, const char *path)
        int ret;
 
        ctx.args = args;
-       parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
+       parse_pathspec(&ctx.pathspec, 0, PATHSPEC_PREFER_CWD,
+                      args->prefix, paths);
        ctx.pathspec.recursive = 1;
+       if (args->prefix && read_tree(args->repo, args->tree, &ctx.pathspec,
+                                     reject_outside, args))
+               die(_("pathspec '%s' matches files outside the "
+                     "current directory"), path);
        ret = read_tree(args->repo, args->tree,
                        &ctx.pathspec,
                        reject_entry, &ctx);
@@ -425,9 +484,8 @@ static void parse_pathspec_arg(const char **pathspec,
         * Also if pathspec patterns are dependent, we're in big
         * trouble as we test each one separately
         */
-       parse_pathspec(&ar_args->pathspec, 0,
-                      PATHSPEC_PREFER_FULL,
-                      "", pathspec);
+       parse_pathspec(&ar_args->pathspec, 0, PATHSPEC_PREFER_CWD,
+                      ar_args->prefix, pathspec);
        ar_args->pathspec.recursive = 1;
        if (pathspec) {
                while (*pathspec) {
@@ -439,8 +497,7 @@ static void parse_pathspec_arg(const char **pathspec,
 }
 
 static void parse_treeish_arg(const char **argv,
-               struct archiver_args *ar_args, const char *prefix,
-               int remote)
+                             struct archiver_args *ar_args, int remote)
 {
        const char *name = argv[0];
        const struct object_id *commit_oid;
@@ -455,13 +512,14 @@ static void parse_treeish_arg(const char **argv,
                const char *colon = strchrnul(name, ':');
                int refnamelen = colon - name;
 
-               if (!dwim_ref(name, refnamelen, &oid, &ref, 0))
+               if (!repo_dwim_ref(the_repository, name, refnamelen, &oid, &ref, 0))
                        die(_("no such ref: %.*s"), refnamelen, name);
        } else {
-               dwim_ref(name, strlen(name), &oid, &ref, 0);
+               repo_dwim_ref(the_repository, name, strlen(name), &oid, &ref,
+                             0);
        }
 
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                die(_("not a valid object name: %s"), name);
 
        commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1);
@@ -479,20 +537,6 @@ static void parse_treeish_arg(const char **argv,
        if (!tree)
                die(_("not a tree object: %s"), oid_to_hex(&oid));
 
-       if (prefix) {
-               struct object_id tree_oid;
-               unsigned short mode;
-               int err;
-
-               err = get_tree_entry(ar_args->repo,
-                                    &tree->object.oid,
-                                    prefix, &tree_oid,
-                                    &mode);
-               if (err || !S_ISDIR(mode))
-                       die(_("current working directory is untracked"));
-
-               tree = parse_tree_indirect(&tree_oid);
-       }
        ar_args->refname = ref;
        ar_args->tree = tree;
        ar_args->commit_oid = commit_oid;
@@ -710,7 +754,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
                setup_git_directory();
        }
 
-       parse_treeish_arg(argv, &args, prefix, remote);
+       parse_treeish_arg(argv, &args, remote);
        parse_pathspec_arg(argv + 1, &args);
 
        rc = ar->write_archive(ar, &args);
index 7178e2a9a2d06c5c3eaaa8884464e6f4cc26fbde..3a4bdfbd078109680dd54143d03ee2567a0cba31 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -1,8 +1,9 @@
 #ifndef ARCHIVE_H
 #define ARCHIVE_H
 
-#include "cache.h"
+#include "object-name.h"
 #include "pathspec.h"
+#include "string-list.h"
 
 struct repository;
 struct pretty_print_context;
diff --git a/attr.c b/attr.c
index 1053dfcd4b61b56e99df60e469ec4e757c80e860..ff0a3e7b61ad0468de7d42305ffc723fbfb9c9e1 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -6,16 +6,23 @@
  * an insanely large number of attributes.
  */
 
-#include "cache.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__true[] = "(builtin)true";
 const char git_attr__false[] = "\0(builtin)false";
@@ -864,7 +871,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)
@@ -872,7 +879,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");
@@ -880,7 +887,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);
 }
@@ -914,14 +921,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);
        }
 
@@ -1165,11 +1172,42 @@ static void collect_some_attrs(struct index_state *istate,
        fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
 }
 
+static const char *default_attr_source_tree_object_name;
+
+void set_git_attr_source(const char *tree_object_name)
+{
+       default_attr_source_tree_object_name = xstrdup(tree_object_name);
+}
+
+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 || !is_null_oid(attr_source))
+               return;
+
+       if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source))
+               die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+}
+
+static struct object_id *default_attr_source(void)
+{
+       static struct object_id attr_source;
+
+       if (is_null_oid(&attr_source))
+               compute_default_attr_source(&attr_source);
+       if (is_null_oid(&attr_source))
+               return NULL;
+       return &attr_source;
+}
+
 void git_check_attr(struct index_state *istate,
-                   const struct object_id *tree_oid, const char *path,
+                   const char *path,
                    struct attr_check *check)
 {
        int i;
+       const struct object_id *tree_oid = default_attr_source();
 
        collect_some_attrs(istate, tree_oid, path, check);
 
@@ -1182,10 +1220,11 @@ void git_check_attr(struct index_state *istate,
        }
 }
 
-void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
+void git_all_attrs(struct index_state *istate,
                   const char *path, struct attr_check *check)
 {
        int i;
+       const struct object_id *tree_oid = default_attr_source();
 
        attr_check_reset(check);
        collect_some_attrs(istate, tree_oid, path, check);
diff --git a/attr.h b/attr.h
index 9884ea2bc60fb4816ed11222b4c820a855f22a24..2b745df4054d7a5fe5e537ac4d894ccbd199b9c4 100644 (file)
--- a/attr.h
+++ b/attr.h
@@ -45,7 +45,7 @@
  * const char *path;
  *
  * setup_check();
- * git_check_attr(&the_index, tree_oid, path, check);
+ * git_check_attr(&the_index, path, check);
  * ------------
  *
  * - Act on `.value` member of the result, left in `check->items[]`:
 #define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
 
 struct index_state;
-struct object_id;
 
 /**
  * An attribute is an opaque object that is identified by its name. Pass the
@@ -135,6 +134,12 @@ struct git_attr;
 struct all_attrs_item;
 struct attr_stack;
 
+/*
+ * The textual object name for the tree-ish used by git_check_attr()
+ * to read attributes from (instead of from the working tree).
+ */
+void set_git_attr_source(const char *);
+
 /*
  * Given a string, return the gitattribute object that
  * corresponds to it.
@@ -203,14 +208,14 @@ void attr_check_free(struct attr_check *check);
 const char *git_attr_name(const struct git_attr *);
 
 void git_check_attr(struct index_state *istate,
-                   const struct object_id *tree_oid, const char *path,
+                   const char *path,
                    struct attr_check *check);
 
 /*
  * Retrieve all attributes that apply to the specified path.
  * check holds the attributes and their values.
  */
-void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
+void git_all_attrs(struct index_state *istate,
                   const char *path, struct attr_check *check);
 
 enum git_attr_direction {
@@ -222,4 +227,13 @@ 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);
+
 #endif /* ATTR_H */
index 6ccf46bc197e8cce014421f803e07e1f8f9d4963..44e76bd90af76938f04f7e7b0df8818d4bb81e61 100644 (file)
--- a/banned.h
+++ b/banned.h
 #define strncpy(x,y,n) BANNED(strncpy)
 #undef strncat
 #define strncat(x,y,n) BANNED(strncat)
+#undef strtok
+#define strtok(x,y) BANNED(strtok)
+#undef strtok_r
+#define strtok_r(x,y,z) BANNED(strtok_r)
 
 #undef sprintf
 #undef vsprintf
index 5ca601ee14fd2ab3b78577aa22a5db778bc7fbe0..bbacdca31b3bc3c1020d49e8e0c4c539a1232cbc 100644 (file)
--- a/base85.c
+++ b/base85.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "base85.h"
 
 #undef DEBUG_85
 
diff --git a/base85.h b/base85.h
new file mode 100644 (file)
index 0000000..c835086
--- /dev/null
+++ b/base85.h
@@ -0,0 +1,7 @@
+#ifndef BASE85_H
+#define BASE85_H
+
+int decode_85(char *dst, const char *line, int linelen);
+void encode_85(char *buf, const unsigned char *data, int bytes);
+
+#endif /* BASE85_H */
index ef5ee5a6436f066e33510219e9a0f73b09bf7aaf..1be8e0a2711df9d29c1ba903fd4e8901379ea406 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "commit.h"
 #include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "revision.h"
 #include "refs.h"
 #include "list-objects.h"
@@ -14,7 +17,9 @@
 #include "strvec.h"
 #include "commit-slab.h"
 #include "commit-reach.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "dir.h"
 
 static struct oid_array good_revs;
@@ -148,8 +153,9 @@ static void show_list(const char *debug, int counted, int nr,
                unsigned commit_flags = commit->object.flags;
                enum object_type type;
                unsigned long size;
-               char *buf = read_object_file(&commit->object.oid, &type,
-                                            &size);
+               char *buf = repo_read_object_file(the_repository,
+                                                 &commit->object.oid, &type,
+                                                 &size);
                const char *subject_start;
                int subject_len;
 
@@ -751,7 +757,8 @@ enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
        }
 
        commit = lookup_commit_reference(the_repository, bisect_rev);
-       format_commit_message(commit, "[%H] %s%n", &commit_msg, &pp);
+       repo_format_commit_message(the_repository, commit, "[%H] %s%n",
+                                  &commit_msg, &pp);
        fputs(commit_msg.buf, stdout);
        strbuf_release(&commit_msg);
 
@@ -846,7 +853,8 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int
        enum bisect_error res = BISECT_OK;
        struct commit_list *result;
 
-       result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);
+       result = repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
+                                          rev + 1);
 
        for (; result; result = result->next) {
                const struct object_id *mb = &result->item->object.oid;
diff --git a/blame.c b/blame.c
index 8bfeaa1c63aedc151b1125e98f52229842d48b19..141756975bf5a58a1744eda78c1750d9d949272f 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -1,11 +1,18 @@
-#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"
 #include "diff.h"
 #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"
 #include "blame.h"
 #include "alloc.h"
 #include "commit-slab.h"
@@ -176,12 +183,12 @@ static void set_commit_buffer_from_strbuf(struct repository *r,
 static struct commit *fake_working_tree_commit(struct repository *r,
                                               struct diff_options *opt,
                                               const char *path,
-                                              const char *contents_from)
+                                              const char *contents_from,
+                                              struct object_id *oid)
 {
        struct commit *commit;
        struct blame_origin *origin;
        struct commit_list **parent_tail, *parent;
-       struct object_id head_oid;
        struct strbuf buf = STRBUF_INIT;
        const char *ident;
        time_t now;
@@ -197,17 +204,18 @@ static struct commit *fake_working_tree_commit(struct repository *r,
        commit->date = now;
        parent_tail = &commit->parents;
 
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
-               die("no such ref: HEAD");
-
-       parent_tail = append_parent(r, parent_tail, &head_oid);
+       parent_tail = append_parent(r, parent_tail, oid);
        append_merge_parents(r, parent_tail);
        verify_working_tree_path(r, commit, path);
 
        origin = make_origin(commit, path);
 
-       ident = fmt_ident("Not Committed Yet", "not.committed.yet",
-                       WANT_BLANK_IDENT, NULL, 0);
+       if (contents_from)
+               ident = fmt_ident("External file (--contents)", "external.file",
+                                 WANT_BLANK_IDENT, NULL, 0);
+       else
+               ident = fmt_ident("Not Committed Yet", "not.committed.yet",
+                                 WANT_BLANK_IDENT, NULL, 0);
        strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
        for (parent = commit->parents; parent; parent = parent->next)
                strbuf_addf(&msg, "parent %s\n",
@@ -1028,8 +1036,9 @@ static void fill_origin_blob(struct diff_options *opt,
                                    &o->blob_oid, 1, &file->ptr, &file_size))
                        ;
                else
-                       file->ptr = read_object_file(&o->blob_oid, &type,
-                                                    &file_size);
+                       file->ptr = repo_read_object_file(the_repository,
+                                                         &o->blob_oid, &type,
+                                                         &file_size);
                file->size = file_size;
 
                if (!file->ptr)
@@ -2429,7 +2438,7 @@ static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin,
 
                        if (sg_origin[i])
                                continue;
-                       if (parse_commit(p))
+                       if (repo_parse_commit(the_repository, p))
                                continue;
                        porigin = find(sb->repo, p, origin, sb->bloom_data);
                        if (!porigin)
@@ -2592,7 +2601,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
                 * so hold onto it in the meantime.
                 */
                blame_origin_incref(suspect);
-               parse_commit(commit);
+               repo_parse_commit(the_repository, commit);
                if (sb->reverse ||
                    (!(commit->object.flags & UNINTERESTING) &&
                     !(revs->max_age != -1 && commit->date < revs->max_age)))
@@ -2771,22 +2780,39 @@ void setup_scoreboard(struct blame_scoreboard *sb,
                sb->commits.compare = compare_commits_by_reverse_commit_date;
        }
 
-       if (sb->final && sb->contents_from)
-               die(_("cannot use --contents with final commit object name"));
-
        if (sb->reverse && sb->revs->first_parent_only)
                sb->revs->children.name = NULL;
 
-       if (!sb->final) {
+       if (sb->contents_from || !sb->final) {
+               struct object_id head_oid, *parent_oid;
+
                /*
-                * "--not A B -- path" without anything positive;
-                * do not default to HEAD, but use the working tree
-                * or "--contents".
+                * Build a fake commit at the top of the history, when
+                * (1) "git blame [^A] --path", i.e. with no positive end
+                *     of the history range, in which case we build such
+                *     a fake commit on top of the HEAD to blame in-tree
+                *     modifications.
+                * (2) "git blame --contents=file [A] -- path", with or
+                *     without positive end of the history range but with
+                *     --contents, in which case we pretend that there is
+                *     a fake commit on top of the positive end (defaulting to
+                *     HEAD) that has the given contents in the path.
                 */
-               setup_work_tree();
+               if (sb->final) {
+                       parent_oid = &sb->final->object.oid;
+               } else {
+                       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+                               die("no such ref: HEAD");
+                       parent_oid = &head_oid;
+               }
+
+               if (!sb->contents_from)
+                       setup_work_tree();
+
                sb->final = fake_working_tree_commit(sb->repo,
                                                     &sb->revs->diffopt,
-                                                    sb->path, sb->contents_from);
+                                                    sb->path, sb->contents_from,
+                                                    parent_oid);
                add_pending_object(sb->revs, &(sb->final->object), ":");
        }
 
@@ -2838,8 +2864,10 @@ void setup_scoreboard(struct blame_scoreboard *sb,
                                    &sb->final_buf_size))
                        ;
                else
-                       sb->final_buf = read_object_file(&o->blob_oid, &type,
-                                                        &sb->final_buf_size);
+                       sb->final_buf = repo_read_object_file(the_repository,
+                                                             &o->blob_oid,
+                                                             &type,
+                                                             &sb->final_buf_size);
 
                if (!sb->final_buf)
                        die(_("cannot read blob %s for path %s"),
diff --git a/blame.h b/blame.h
index 38bde535b3d46461d0619bc68c852210693de571..31ddc85f19e359908710162ad4aa144784dec16b 100644 (file)
--- a/blame.h
+++ b/blame.h
@@ -1,8 +1,8 @@
 #ifndef BLAME_H
 #define BLAME_H
 
-#include "cache.h"
 #include "commit.h"
+#include "oidset.h"
 #include "xdiff-interface.h"
 #include "revision.h"
 #include "prio-queue.h"
diff --git a/blob.c b/blob.c
index 8f83523b0cde6dbf1b808b3dcf8ab1c1c23085f3..888e28a5594747bd263df0bb8f2179122bccb131 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "blob.h"
 #include "repository.h"
 #include "alloc.h"
diff --git a/bloom.c b/bloom.c
index d0730525da51f783e0f72f502a62db4407bd7ad9..aef6b5fea2d18f521b4812bd017fe685f635be47 100644 (file)
--- a/bloom.c
+++ b/bloom.c
@@ -6,6 +6,7 @@
 #include "hashmap.h"
 #include "commit-graph.h"
 #include "commit.h"
+#include "commit-slab.h"
 
 define_commit_slab(bloom_filter_slab, struct bloom_filter);
 
index e5614b53b3699d9fc08d41135b16a4a875b0fc68..3e4684f79f693059a6272465dd983e149aee5eb9 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -1,10 +1,16 @@
 #include "git-compat-util.h"
-#include "cache.h"
+#include "advice.h"
 #include "config.h"
 #include "branch.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "path.h"
 #include "refs.h"
 #include "refspec.h"
 #include "remote.h"
+#include "repository.h"
 #include "sequencer.h"
 #include "commit.h"
 #include "worktree.h"
@@ -32,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:
@@ -228,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;
@@ -328,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)
@@ -465,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;
@@ -475,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)
@@ -531,7 +540,7 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
                explicit_tracking = 1;
 
        real_ref = NULL;
-       if (get_oid_mb(start_name, &oid)) {
+       if (repo_get_oid_mb(r, start_name, &oid)) {
                if (explicit_tracking) {
                        int code = die_message(_(upstream_missing), start_name);
                        advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
@@ -541,7 +550,8 @@ static void dwim_branch_start(struct repository *r, const char *start_name,
                die(_("not a valid object name: '%s'"), start_name);
        }
 
-       switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref, 0)) {
+       switch (repo_dwim_ref(r, start_name, strlen(start_name), &oid,
+                             &real_ref, 0)) {
        case 0:
                /* Not branching from any existing branch */
                if (explicit_tracking)
@@ -632,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);
 }
 
 /**
@@ -772,7 +783,7 @@ void create_branches_recursively(struct repository *r, const char *name,
                            name);
        }
 
-       create_branch(the_repository, name, start_commitish, force, 0, reflog, quiet,
+       create_branch(r, name, start_commitish, force, 0, reflog, quiet,
                      BRANCH_TRACK_NEVER, dry_run);
        if (dry_run)
                return;
@@ -820,40 +831,17 @@ void remove_branch_state(struct repository *r, int verbose)
 void die_if_checked_out(const char *branch, int ignore_current_worktree)
 {
        struct worktree **worktrees = get_worktrees();
-       const struct worktree *wt;
-
-       wt = find_shared_symref(worktrees, "HEAD", branch);
-       if (wt && (!ignore_current_worktree || !wt->is_current)) {
-               skip_prefix(branch, "refs/heads/", &branch);
-               die(_("'%s' is already checked out at '%s'"), branch, wt->path);
-       }
-
-       free_worktrees(worktrees);
-}
-
-int replace_each_worktree_head_symref(const char *oldref, const char *newref,
-                                     const char *logmsg)
-{
-       int ret = 0;
-       struct worktree **worktrees = get_worktrees();
-       int i;
-
-       for (i = 0; worktrees[i]; i++) {
-               struct ref_store *refs;
 
-               if (worktrees[i]->is_detached)
-                       continue;
-               if (!worktrees[i]->head_ref)
-                       continue;
-               if (strcmp(oldref, worktrees[i]->head_ref))
+       for (int i = 0; worktrees[i]; i++) {
+               if (worktrees[i]->is_current && ignore_current_worktree)
                        continue;
 
-               refs = get_worktree_ref_store(worktrees[i]);
-               if (refs_create_symref(refs, "HEAD", newref, logmsg))
-                       ret = error(_("HEAD of working tree %s is not updated"),
-                                   worktrees[i]->path);
+               if (is_shared_symref(worktrees[i], "HEAD", branch)) {
+                       skip_prefix(branch, "refs/heads/", &branch);
+                       die(_("'%s' is already checked out at '%s'"),
+                               branch, worktrees[i]->path);
+               }
        }
 
        free_worktrees(worktrees);
-       return ret;
 }
index ef56103c050fa09d6087e2bade7f24240d79ae04..30c01aed73d7b7751b87cfb4c5cd55387c8b8bb9 100644 (file)
--- a/branch.h
+++ b/branch.h
@@ -155,12 +155,4 @@ int read_branch_desc(struct strbuf *, const char *branch_name);
  */
 void die_if_checked_out(const char *branch, int ignore_current_worktree);
 
-/*
- * Update all per-worktree HEADs pointing at the old ref to point the new ref.
- * This will be used when renaming a branch. Returns 0 if successful, non-zero
- * otherwise.
- */
-int replace_each_worktree_head_symref(const char *oldref, const char *newref,
-                                     const char *logmsg);
-
 #endif
index 46cc7897898a51a7039e5bc9d0c350f3fab2f75e..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
@@ -107,6 +104,16 @@ void setup_auto_pager(const char *cmd, int def);
 
 int is_builtin(const char *s);
 
+/*
+ * Builtins which do not use RUN_SETUP should never see
+ * a prefix that is not empty; use this to protect downstream
+ * code which is not prepared to call prefix_filename(), etc.
+ */
+#define BUG_ON_NON_EMPTY_PREFIX(prefix) do { \
+       if ((prefix)) \
+               BUG("unexpected prefix in builtin: %s", (prefix)); \
+} while (0)
+
 int cmd_add(int argc, const char **argv, const char *prefix);
 int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
index 61dd386d109b3756e90756b91d9405c71d1b4145..12c5aa6d1f377fb7d009481380b13aeeb0787e36 100644 (file)
@@ -4,18 +4,24 @@
  * Copyright (C) 2006 Linus Torvalds
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "advice.h"
+#include "config.h"
 #include "lockfile.h"
+#include "editor.h"
 #include "dir.h"
+#include "gettext.h"
 #include "pathspec.h"
 #include "exec-cmd.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"
@@ -33,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;
@@ -66,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;
@@ -282,8 +194,7 @@ 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"));
@@ -354,7 +265,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")) {
@@ -362,7 +274,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_(
@@ -637,7 +552,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);
index e0848ddadfeb26617bcf2188b034a3968d1e0b67..202040b62e4784a3c1d43cdea3f4cdc6171324f9 100644 (file)
@@ -4,10 +4,15 @@
  * Based on git-am.sh by Junio C Hamano.
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
 #include "exec-cmd.h"
+#include "gettext.h"
+#include "hex.h"
 #include "parse-options.h"
 #include "dir.h"
 #include "run-command.h"
@@ -22,6 +27,8 @@
 #include "diffcore.h"
 #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"
@@ -33,6 +40,8 @@
 #include "apply.h"
 #include "string-list.h"
 #include "packfile.h"
+#include "pager.h"
+#include "path.h"
 #include "repository.h"
 #include "pretty.h"
 
@@ -777,7 +786,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;
@@ -860,7 +869,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;
@@ -1066,7 +1075,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
        else
                write_state_text(state, "applying", "");
 
-       if (!get_oid("HEAD", &curr_head)) {
+       if (!repo_get_oid(the_repository, "HEAD", &curr_head)) {
                write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
                if (!state->rebasing)
                        update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
@@ -1109,7 +1118,7 @@ static void am_next(struct am_state *state)
        unlink(am_path(state, "original-commit"));
        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
 
-       if (!get_oid("HEAD", &head))
+       if (!repo_get_oid(the_repository, "HEAD", &head))
                write_state_text(state, "abort-safety", oid_to_hex(&head));
        else
                write_state_text(state, "abort-safety", "");
@@ -1274,7 +1283,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);
@@ -1329,7 +1338,8 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
        size_t ident_len;
        struct ident_split id;
 
-       buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+       buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+                                     get_commit_output_encoding());
 
        ident_line = find_commit_header(buffer, "author", &ident_len);
        if (!ident_line)
@@ -1361,7 +1371,7 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
                die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
        state->msg = xstrdup(msg + 2);
        state->msg_len = strlen(state->msg);
-       unuse_commit_buffer(commit, buffer);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
 }
 
 /**
@@ -1402,9 +1412,9 @@ static void write_index_patch(const struct am_state *state)
        struct rev_info rev_info;
        FILE *fp;
 
-       if (!get_oid("HEAD", &head)) {
+       if (!repo_get_oid(the_repository, "HEAD", &head)) {
                struct commit *commit = lookup_commit_or_die(&head, "HEAD");
-               tree = get_commit_tree(commit);
+               tree = repo_get_commit_tree(the_repository, commit);
        } else
                tree = lookup_tree(the_repository,
                                   the_repository->hash_algo->empty_tree);
@@ -1420,7 +1430,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);
 }
 
@@ -1556,7 +1566,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
        struct commit *result;
        char *their_tree_name;
 
-       if (get_oid("HEAD", &our_tree) < 0)
+       if (repo_get_oid(the_repository, "HEAD", &our_tree) < 0)
                oidcpy(&our_tree, the_hash_algo->empty_tree);
 
        if (build_fake_ancestor(state, index_path))
@@ -1583,7 +1593,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);
        }
 
@@ -1646,7 +1656,7 @@ static void do_commit(const struct am_state *state)
        if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
                die(_("git write-tree failed to write a tree"));
 
-       if (!get_oid_commit("HEAD", &parent)) {
+       if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
                old_oid = &parent;
                commit_list_insert(lookup_commit(the_repository, &parent),
                                   &parents);
@@ -2088,7 +2098,7 @@ static void am_skip(struct am_state *state)
 
        am_rerere_clear();
 
-       if (get_oid("HEAD", &head))
+       if (repo_get_oid(the_repository, "HEAD", &head))
                oidcpy(&head, the_hash_algo->empty_tree);
 
        if (clean_index(&head, &head))
@@ -2130,7 +2140,7 @@ static int safe_to_abort(const struct am_state *state)
                oidclr(&abort_safety);
        strbuf_release(&sb);
 
-       if (get_oid("HEAD", &head))
+       if (repo_get_oid(the_repository, "HEAD", &head))
                oidclr(&head);
 
        if (oideq(&head, &abort_safety))
@@ -2163,7 +2173,7 @@ static void am_abort(struct am_state *state)
        if (!has_curr_head)
                oidcpy(&curr_head, the_hash_algo->empty_tree);
 
-       has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
+       has_orig_head = !repo_get_oid(the_repository, "ORIG_HEAD", &orig_head);
        if (!has_orig_head)
                oidcpy(&orig_head, the_hash_algo->empty_tree);
 
@@ -2300,17 +2310,6 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
        return 0;
 }
 
-static int git_am_config(const char *k, const char *v, void *cb UNUSED)
-{
-       int status;
-
-       status = git_gpg_config(k, v, NULL);
-       if (status)
-               return status;
-
-       return git_default_config(k, v, NULL);
-}
-
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
        struct am_state state;
@@ -2348,12 +2347,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"),
@@ -2434,7 +2430,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(usage, options);
 
-       git_config(git_am_config, NULL);
+       git_config(git_default_config, NULL);
 
        am_state_init(&state);
 
index 555219de40fa7e3097612a60eb953f81580a8de9..c18b7ea5d3da4aa66d82c9fa0e911274308ad598 100644 (file)
@@ -1,6 +1,7 @@
-#include "cache.h"
 #include "builtin.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "repository.h"
 #include "apply.h"
 
 static const char * const apply_usage[] = {
index f094390ee01f810e7035f2efc2be75deedc3befa..90761fdfee0f58f0d2d8cca9c7b0bcd6e0ee7fe9 100644 (file)
@@ -2,12 +2,13 @@
  * Copyright (c) 2006 Franck Bui-Huu
  * Copyright (c) 2006 Rene Scharfe
  */
-#include "cache.h"
 #include "builtin.h"
 #include "archive.h"
+#include "gettext.h"
 #include "transport.h"
 #include "parse-options.h"
 #include "pkt-line.h"
+#include "repository.h"
 #include "sideband.h"
 
 static void create_output_file(const char *output_file)
@@ -81,7 +82,7 @@ static int run_remote_archiver(int argc, const char **argv,
 int cmd_archive(int argc, const char **argv, const char *prefix)
 {
        const char *exec = "git-upload-archive";
-       const char *output = NULL;
+       char *output = NULL;
        const char *remote = NULL;
        struct option local_opts[] = {
                OPT_FILENAME('o', "output", &output,
@@ -106,5 +107,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
 
        setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 
+       UNLEAK(output);
        return write_archive(argc, argv, prefix, the_repository, output, 0);
 }
index 73017402671d30ce7f868a9691f9bb6f520695e1..65478ef40f54e35cbed33234209fc3fac8b4e99b 100644 (file)
@@ -1,11 +1,17 @@
 #include "builtin.h"
-#include "cache.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
 #include "parse-options.h"
 #include "bisect.h"
 #include "refs.h"
 #include "dir.h"
 #include "strvec.h"
 #include "run-command.h"
+#include "oid-array.h"
+#include "path.h"
 #include "prompt.h"
 #include "quote.h"
 #include "revision.h"
@@ -235,7 +241,7 @@ static int bisect_reset(const char *commit)
        } else {
                struct object_id oid;
 
-               if (get_oid_commit(commit, &oid))
+               if (repo_get_oid_commit(the_repository, commit, &oid))
                        return error(_("'%s' is not a valid commit"), commit);
                strbuf_addstr(&branch, commit);
        }
@@ -244,7 +250,8 @@ static int bisect_reset(const char *commit)
                struct child_process cmd = CHILD_PROCESS_INIT;
 
                cmd.git_cmd = 1;
-               strvec_pushl(&cmd.args, "checkout", branch.buf, "--", NULL);
+               strvec_pushl(&cmd.args, "checkout", "--ignore-other-worktrees",
+                               branch.buf, "--", NULL);
                if (run_command(&cmd)) {
                        error(_("could not check out original"
                                " HEAD '%s'. Try 'git bisect"
@@ -265,7 +272,8 @@ static void log_commit(FILE *fp, char *fmt, const char *state,
        struct strbuf commit_msg = STRBUF_INIT;
        char *label = xstrfmt(fmt, state);
 
-       format_commit_message(commit, "%s", &commit_msg, &pp);
+       repo_format_commit_message(the_repository, commit, "%s", &commit_msg,
+                                  &pp);
 
        fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
                commit_msg.buf);
@@ -292,7 +300,7 @@ static int bisect_write(const char *state, const char *rev,
                goto finish;
        }
 
-       if (get_oid(rev, &oid)) {
+       if (repo_get_oid(the_repository, rev, &oid)) {
                res = error(_("couldn't get the oid of the rev '%s'"), rev);
                goto finish;
        }
@@ -567,7 +575,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
         * sets up a revision walk.
         */
        reset_revision_walk();
-       init_revisions(revs, NULL);
+       repo_init_revisions(the_repository, revs, NULL);
        setup_revisions(0, NULL, revs, NULL);
        for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
        cb.object_flags = UNINTERESTING;
@@ -603,8 +611,8 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 
        while ((commit = get_revision(&revs)) != NULL) {
                strbuf_reset(&commit_name);
-               format_commit_message(commit, "%s",
-                                     &commit_name, &pp);
+               repo_format_commit_message(the_repository, commit, "%s",
+                                          &commit_name, &pp);
                fprintf(fp, "# possible first %s commit: [%s] %s\n",
                        terms->term_bad, oid_to_hex(&commit->object.oid),
                        commit_name.buf);
@@ -633,7 +641,8 @@ static int bisect_successful(struct bisect_terms *terms)
 
        read_ref(bad_ref, &oid);
        commit = lookup_commit_reference_by_name(bad_ref);
-       format_commit_message(commit, "%s", &commit_name, &pp);
+       repo_format_commit_message(the_repository, commit, "%s", &commit_name,
+                                  &pp);
 
        res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
                            terms->term_bad, oid_to_hex(&commit->object.oid),
@@ -775,7 +784,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
         */
        head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
        if (!head)
-               if (get_oid("HEAD", &head_oid))
+               if (repo_get_oid(the_repository, "HEAD", &head_oid))
                        return error(_("bad HEAD - I need a HEAD"));
 
        /*
@@ -801,11 +810,11 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
                }
        } else {
                /* Get the rev from where we start. */
-               if (!get_oid(head, &head_oid) &&
+               if (!repo_get_oid(the_repository, head, &head_oid) &&
                    !starts_with(head, "refs/heads/")) {
                        strbuf_reset(&start_head);
                        strbuf_addstr(&start_head, oid_to_hex(&head_oid));
-               } else if (!get_oid(head, &head_oid) &&
+               } else if (!repo_get_oid(the_repository, head, &head_oid) &&
                           skip_prefix(head, "refs/heads/", &head)) {
                        strbuf_addstr(&start_head, head);
                } else {
@@ -828,7 +837,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
                write_file(git_path_bisect_first_parent(), "\n");
 
        if (no_checkout) {
-               if (get_oid(start_head.buf, &oid) < 0) {
+               if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
                        res = error(_("invalid ref: '%s'"), start_head.buf);
                        goto finish;
                }
@@ -933,11 +942,12 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
 
        if (argc == 0) {
                const char *head = "BISECT_HEAD";
-               enum get_oid_result res_head = get_oid(head, &oid);
+               enum get_oid_result res_head = repo_get_oid(the_repository,
+                                                           head, &oid);
 
                if (res_head == MISSING_OBJECT) {
                        head = "HEAD";
-                       res_head = get_oid(head, &oid);
+                       res_head = repo_get_oid(the_repository, head, &oid);
                }
 
                if (res_head)
@@ -953,7 +963,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
        for (; argc; argc--, argv++) {
                struct commit *commit;
 
-               if (get_oid(*argv, &oid)){
+               if (repo_get_oid(the_repository, *argv, &oid)){
                        error(_("Bad rev input: %s"), *argv);
                        oid_array_clear(&revs);
                        return BISECT_FAILED;
@@ -1092,7 +1102,7 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
                        struct rev_info revs;
                        struct commit *commit;
 
-                       init_revisions(&revs, NULL);
+                       repo_init_revisions(the_repository, &revs, NULL);
                        setup_revisions(2, argv + i - 1, &revs, NULL);
 
                        if (prepare_revision_walk(&revs))
index 71f925e456c34513b85e64e7dd6a72d510a8307e..9c987d656756e8f436e3b1cb818306097e402e4c 100644 (file)
@@ -5,10 +5,13 @@
  * See COPYING for licensing conditions
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "color.h"
 #include "builtin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "commit.h"
 #include "diff.h"
 #include "line-log.h"
 #include "dir.h"
 #include "progress.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
 #include "blame.h"
 #include "refs.h"
+#include "setup.h"
 #include "tag.h"
+#include "write-or-die.h"
 
 static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
 static char annotate_usage[] = N_("git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>");
@@ -199,13 +206,13 @@ static void get_commit_info(struct commit *commit,
        const char *message;
 
        encoding = get_log_output_encoding();
-       message = logmsg_reencode(commit, NULL, encoding);
+       message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
        get_ac_line(message, "\nauthor ",
                    &ret->author, &ret->author_mail,
                    &ret->author_time, &ret->author_tz);
 
        if (!detailed) {
-               unuse_commit_buffer(commit, message);
+               repo_unuse_commit_buffer(the_repository, commit, message);
                return;
        }
 
@@ -219,7 +226,7 @@ static void get_commit_info(struct commit *commit,
        else
                strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid));
 
-       unuse_commit_buffer(commit, message);
+       repo_unuse_commit_buffer(the_repository, commit, message);
 }
 
 /*
@@ -601,8 +608,9 @@ static int read_ancestry(const char *graft_file)
 
 static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
 {
-       const char *uniq = find_unique_abbrev(&suspect->commit->object.oid,
-                                             auto_abbrev);
+       const char *uniq = repo_find_unique_abbrev(the_repository,
+                                                  &suspect->commit->object.oid,
+                                                  auto_abbrev);
        int len = strlen(uniq);
        if (auto_abbrev < len)
                return len;
@@ -685,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);
@@ -758,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)
@@ -802,7 +811,7 @@ static int is_a_rev(const char *name)
 {
        struct object_id oid;
 
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                return 0;
        return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
 }
@@ -845,7 +854,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,
                                                    peel_to_commit_oid, sb);
        }
        for_each_string_list_item(i, ignore_rev_list) {
-               if (get_oid_committish(i->string, &oid) ||
+               if (repo_get_oid_committish(the_repository, i->string, &oid) ||
                    peel_to_commit_oid(&oid, sb))
                        die(_("cannot find revision %s to ignore"), i->string);
                oidset_insert(&sb->ignore_list, &oid);
index f63fd45edb96b513c24e1a9cd7c8a55e5a5f7b13..08da650516037e2e18b2e99831562db533111254 100644 (file)
@@ -5,16 +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"
@@ -41,6 +45,7 @@ static const char *head;
 static struct object_id head_oid;
 static int recurse_submodules = 0;
 static int submodule_propagate_branches = 0;
+static int omit_empty = 0;
 
 static int branch_use_color = -1;
 static char branch_colors[][COLOR_MAXLEN] = {
@@ -77,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;
 
@@ -111,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)
@@ -150,17 +159,18 @@ static int branch_merged(int kind, const char *name,
        if (!reference_rev)
                reference_rev = head_rev;
 
-       merged = reference_rev ? in_merge_bases(rev, reference_rev) : 0;
+       merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
+                                                    reference_rev) : 0;
 
        /*
         * After the safety valve is fully redefined to "check with
         * upstream, if any, otherwise with HEAD", we should just
-        * return the result of the in_merge_bases() above without
+        * return the result of the repo_in_merge_bases() above without
         * any of the following code, but during the transition period,
         * a gentle reminder is in order.
         */
        if ((head_rev != reference_rev) &&
-           (head_rev ? in_merge_bases(rev, head_rev) : 0) != merged) {
+           (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."),
@@ -216,10 +226,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
        struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
        struct string_list_item *item;
        int branch_name_pos;
+       const char *fmt_remotes = "refs/remotes/%s";
 
        switch (kinds) {
        case FILTER_REFS_REMOTES:
-               fmt = "refs/remotes/%s";
+               fmt = fmt_remotes;
                /* For subsequent UI messages */
                remote_branch = 1;
                allowed_interpret = INTERPRET_BRANCH_REMOTE;
@@ -263,9 +274,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                                        | RESOLVE_REF_ALLOW_BAD_NAME,
                                        &oid, &flags);
                if (!target) {
-                       error(remote_branch
-                             ? _("remote-tracking branch '%s' not found.")
-                             : _("branch '%s' not found."), bname.buf);
+                       if (remote_branch) {
+                               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,
+                                                       RESOLVE_REF_READING
+                                                       | RESOLVE_REF_NO_RECURSE
+                                                       | RESOLVE_REF_ALLOW_BAD_NAME,
+                                                       &oid, &flags);
+                               FREE_AND_NULL(virtual_name);
+
+                               if (virtual_target)
+                                       error(_("branch '%s' not found.\n"
+                                               "Did you forget --remote?"),
+                                               bname.buf);
+                               else
+                                       error(_("branch '%s' not found."), bname.buf);
+                               FREE_AND_NULL(virtual_target);
+                       }
                        ret = 1;
                        continue;
                }
@@ -280,7 +307,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                item = string_list_append(&refs_to_delete, name);
                item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
                                    : (flags & REF_ISSYMREF) ? target
-                                   : find_unique_abbrev(&oid, DEFAULT_ABBREV));
+                                   : repo_find_unique_abbrev(the_repository, &oid, DEFAULT_ABBREV));
 
        next:
                free(target);
@@ -342,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;
 }
 
@@ -448,6 +466,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
        if (verify_ref_format(format))
                die(_("unable to parse format string"));
 
+       filter_ahead_behind(the_repository, format, &array);
        ref_array_sort(sorting, &array);
 
        for (i = 0; i < array.nr; i++) {
@@ -461,7 +480,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
                        string_list_append(output, out.buf);
                } else {
                        fwrite(out.buf, 1, out.len, stdout);
-                       putchar('\n');
+                       if (out.len || !omit_empty)
+                               putchar('\n');
                }
        }
 
@@ -486,9 +506,9 @@ static void print_current_branch_name(void)
                die(_("HEAD (%s) points outside of refs/heads/"), refname);
 }
 
-static void reject_rebase_or_bisect_branch(const char *target)
+static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
+                                          const char *target)
 {
-       struct worktree **worktrees = get_worktrees();
        int i;
 
        for (i = 0; worktrees[i]; i++) {
@@ -505,17 +525,50 @@ static void reject_rebase_or_bisect_branch(const char *target)
                        die(_("Branch %s is being bisected at %s"),
                            target, wt->path);
        }
+}
 
-       free_worktrees(worktrees);
+/*
+ * Update all per-worktree HEADs pointing at the old ref to point the new ref.
+ * This will be used when renaming a branch. Returns 0 if successful, non-zero
+ * otherwise.
+ */
+static int replace_each_worktree_head_symref(struct worktree **worktrees,
+                                            const char *oldref, const char *newref,
+                                            const char *logmsg)
+{
+       int ret = 0;
+       int i;
+
+       for (i = 0; worktrees[i]; i++) {
+               struct ref_store *refs;
+
+               if (worktrees[i]->is_detached)
+                       continue;
+               if (!worktrees[i]->head_ref)
+                       continue;
+               if (strcmp(oldref, worktrees[i]->head_ref))
+                       continue;
+
+               refs = get_worktree_ref_store(worktrees[i]);
+               if (refs_create_symref(refs, "HEAD", newref, logmsg))
+                       ret = error(_("HEAD of working tree %s is not updated"),
+                                   worktrees[i]->path);
+       }
+
+       return ret;
 }
 
+#define IS_HEAD 1
+#define IS_ORPHAN 2
+
 static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
 {
        struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
        struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
        const char *interpreted_oldname = NULL;
        const char *interpreted_newname = NULL;
-       int recovery = 0;
+       int recovery = 0, oldref_usage = 0;
+       struct worktree **worktrees = get_worktrees();
 
        if (strbuf_check_branch_ref(&oldref, oldname)) {
                /*
@@ -528,8 +581,19 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
                        die(_("Invalid branch name: '%s'"), oldname);
        }
 
-       if ((copy || strcmp(head, oldname)) && !ref_exists(oldref.buf)) {
-               if (copy && !strcmp(head, oldname))
+       for (int i = 0; worktrees[i]; i++) {
+               struct worktree *wt = worktrees[i];
+
+               if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref)) {
+                       oldref_usage |= IS_HEAD;
+                       if (is_null_oid(&wt->head_oid))
+                               oldref_usage |= IS_ORPHAN;
+                       break;
+               }
+       }
+
+       if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
+               if (oldref_usage & IS_HEAD)
                        die(_("No commit on branch '%s' yet."), oldname);
                else
                        die(_("No branch named '%s'."), oldname);
@@ -544,7 +608,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
        else
                validate_new_branchname(newname, &newref, force);
 
-       reject_rebase_or_bisect_branch(oldref.buf);
+       reject_rebase_or_bisect_branch(worktrees, oldref.buf);
 
        if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
            !skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
@@ -558,8 +622,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
                strbuf_addf(&logmsg, "Branch: renamed %s to %s",
                            oldref.buf, newref.buf);
 
-       if (!copy &&
-           (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+       if (!copy && !(oldref_usage & IS_ORPHAN) &&
            rename_ref(oldref.buf, newref.buf, logmsg.buf))
                die(_("Branch rename failed"));
        if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
@@ -574,8 +637,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
                                interpreted_oldname);
        }
 
-       if (!copy &&
-           replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
+       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);
 
        strbuf_release(&logmsg);
@@ -590,6 +654,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
        strbuf_release(&newref);
        strbuf_release(&oldsection);
        strbuf_release(&newsection);
+       free_worktrees(worktrees);
 }
 
 static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
@@ -603,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"),
@@ -614,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)
@@ -636,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;
@@ -655,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")),
@@ -664,12 +730,15 @@ 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),
                OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+               OPT_BOOL(0, "omit-empty",  &omit_empty,
+                       N_("do not output a newline after empty formatted refs")),
                OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
                OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
                OPT_BOOL('l', "list", &list, N_("list branch names")),
@@ -692,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;
 
@@ -759,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"));
@@ -786,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;
@@ -806,7 +877,7 @@ 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 || !strcmp(head, branch_name))
+                       error((!argc || branch_checked_out(branch_ref.buf))
                              ? _("No commit on branch '%s' yet.")
                              : _("No branch named '%s'."),
                              branch_name);
@@ -851,7 +922,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                }
 
                if (!ref_exists(branch->refname)) {
-                       if (!argc || !strcmp(head, branch->name))
+                       if (!argc || branch_checked_out(branch->refname))
                                die(_("No commit on branch '%s' yet."), branch->name);
                        die(_("branch '%s' does not exist"), branch->name);
                }
index 5bc254be80f97e7bb33c732039b7bab620fb71ad..d2ae5c305db82cda78851196411f6437f4abbda9 100644 (file)
@@ -1,4 +1,7 @@
 #include "builtin.h"
+#include "abspath.h"
+#include "editor.h"
+#include "gettext.h"
 #include "parse-options.h"
 #include "strbuf.h"
 #include "help.h"
@@ -6,7 +9,8 @@
 #include "hook.h"
 #include "hook-list.h"
 #include "diagnose.h"
-
+#include "object-file.h"
+#include "setup.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
index acceef6200172cf7a44de45bfa6f3e940b6444c9..3ad11dc5d0548727da0f27e04563a8d947207f74 100644 (file)
@@ -1,7 +1,11 @@
 #include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "setup.h"
 #include "strvec.h"
 #include "parse-options.h"
-#include "cache.h"
+#include "pkt-line.h"
+#include "repository.h"
 #include "bundle.h"
 
 /*
@@ -12,7 +16,7 @@
  */
 
 #define BUILTIN_BUNDLE_CREATE_USAGE \
-       N_("git bundle create [-q | --quiet | --progress | --all-progress] [--all-progress-implied]\n" \
+       N_("git bundle create [-q | --quiet | --progress]\n" \
           "                  [--version=<version>] <file> <git-rev-list-args>")
 #define BUILTIN_BUNDLE_VERIFY_USAGE \
        N_("git bundle verify [-q | --quiet] <file>")
@@ -59,46 +63,41 @@ static int parse_options_cmd_bundle(int argc,
                             PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc)
                usage_msg_opt(_("need a <file> argument"), usagestr, options);
-       *bundle_file = prefix_filename(prefix, argv[0]);
+       *bundle_file = prefix_filename_except_for_dash(prefix, argv[0]);
        return argc;
 }
 
 static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
-       int all_progress_implied = 0;
-       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(0, "all-progress", &progress,
-                           N_("show progress meter during object writing phase"), 2),
-               OPT_BOOL(0, "all-progress-implied",
-                        &all_progress_implied,
-                        N_("similar to --all-progress when progress meter is shown")),
+               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);
@@ -107,6 +106,23 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
        return ret;
 }
 
+/*
+ * Similar to read_bundle_header(), but handle "-" as stdin.
+ */
+static int open_bundle(const char *path, struct bundle_header *header,
+                      const char **name)
+{
+       if (!strcmp(path, "-")) {
+               if (name)
+                       *name = "<stdin>";
+               return read_bundle_header_fd(0, header, "<stdin>");
+       }
+
+       if (name)
+               *name = path;
+       return read_bundle_header(path, header);
+}
+
 static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
        struct bundle_header header = BUNDLE_HEADER_INIT;
        int bundle_fd = -1;
@@ -118,12 +134,13 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
                OPT_END()
        };
        char *bundle_file;
+       const char *name;
 
        argc = parse_options_cmd_bundle(argc, argv, prefix,
                        builtin_bundle_verify_usage, options, &bundle_file);
        /* bundle internals use argv[1] as further parameters */
 
-       if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+       if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
                ret = 1;
                goto cleanup;
        }
@@ -134,7 +151,7 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
                goto cleanup;
        }
 
-       fprintf(stderr, _("%s is okay\n"), bundle_file);
+       fprintf(stderr, _("%s is okay\n"), name);
        ret = 0;
 cleanup:
        free(bundle_file);
@@ -155,7 +172,7 @@ static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix
                        builtin_bundle_list_heads_usage, options, &bundle_file);
        /* bundle internals use argv[1] as further parameters */
 
-       if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+       if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
                ret = 1;
                goto cleanup;
        }
@@ -185,7 +202,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
                        builtin_bundle_unbundle_usage, options, &bundle_file);
        /* bundle internals use argv[1] as further parameters */
 
-       if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+       if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
                ret = 1;
                goto cleanup;
        }
index cc17635e76536471a0a756903a8187eaa01d5733..694c8538df2ff8200e214351e5e857530d2a1191 100644 (file)
@@ -4,19 +4,27 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
+#include "convert.h"
 #include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "ident.h"
 #include "parse-options.h"
 #include "userdiff.h"
 #include "streaming.h"
 #include "tree-walk.h"
 #include "oid-array.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
 #include "promisor-remote.h"
 #include "mailmap.h"
+#include "write-or-die.h"
 
 enum batch_mode {
        BATCH_MODE_CONTENTS,
@@ -32,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;
 };
 
@@ -60,7 +69,7 @@ static int filter_object(const char *path, unsigned mode,
 {
        enum object_type type;
 
-       *buf = read_object_file(oid, &type, size);
+       *buf = repo_read_object_file(the_repository, oid, &type, size);
        if (!*buf)
                return error(_("cannot read object %s '%s'"),
                             oid_to_hex(oid), path);
@@ -152,7 +161,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                goto cleanup;
 
        case 'e':
-               return !has_object_file(&oid);
+               return !repo_has_object_file(the_repository, &oid);
 
        case 'w':
 
@@ -187,7 +196,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        ret = stream_blob(&oid);
                        goto cleanup;
                }
-               buf = read_object_file(&oid, &type, &size);
+               buf = repo_read_object_file(the_repository, &oid, &type,
+                                           &size);
                if (!buf)
                        die("Cannot read object %s", obj_name);
 
@@ -207,8 +217,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                if (exp_type_id == OBJ_BLOB) {
                        struct object_id blob_oid;
                        if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
-                               char *buffer = read_object_file(&oid, &type,
-                                                               &size);
+                               char *buffer = repo_read_object_file(the_repository,
+                                                                    &oid,
+                                                                    &type,
+                                                                    &size);
                                const char *target;
                                if (!skip_prefix(buffer, "object ", &target) ||
                                    get_oid_hex(target, &blob_oid))
@@ -296,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));
@@ -333,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)
@@ -383,9 +395,10 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
                                if (!textconv_object(the_repository,
                                                     data->rest, 0100644, oid,
                                                     1, &contents, &size))
-                                       contents = read_object_file(oid,
-                                                                   &type,
-                                                                   &size);
+                                       contents = repo_read_object_file(the_repository,
+                                                                        oid,
+                                                                        &type,
+                                                                        &size);
                                if (!contents)
                                        die("could not convert '%s' %s",
                                            oid_to_hex(oid), data->rest);
@@ -402,7 +415,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
                unsigned long size;
                void *contents;
 
-               contents = read_object_file(oid, &type, &size);
+               contents = repo_read_object_file(the_repository, oid, &type,
+                                                &size);
 
                if (use_mailmap) {
                        size_t s = size;
@@ -422,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);
 }
 
 /*
@@ -455,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;
                }
@@ -477,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);
        }
 }
 
@@ -505,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",
@@ -532,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;
        }
@@ -559,7 +577,7 @@ static int batch_object_cb(const struct object_id *oid, void *vdata)
 }
 
 static int collect_loose_object(const struct object_id *oid,
-                               const char *path,
+                               const char *path UNUSED,
                                void *data)
 {
        oid_array_append(data, oid);
@@ -567,8 +585,8 @@ static int collect_loose_object(const struct object_id *oid,
 }
 
 static int collect_packed_object(const struct object_id *oid,
-                                struct packed_git *pack,
-                                uint32_t pos,
+                                struct packed_git *pack UNUSED,
+                                uint32_t pos UNUSED,
                                 void *data)
 {
        oid_array_append(data, oid);
@@ -591,7 +609,7 @@ static int batch_unordered_object(const struct object_id *oid,
 }
 
 static int batch_unordered_loose(const struct object_id *oid,
-                                const char *path,
+                                const char *path UNUSED,
                                 void *data)
 {
        return batch_unordered_object(oid, NULL, 0, data);
@@ -679,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))
@@ -762,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);
@@ -787,10 +796,10 @@ static int batch_objects(struct batch_options *opt)
                if (!memcmp(&data.info, &empty, sizeof(empty)))
                        data.skip_object_info = 1;
 
-               if (has_promisor_remote())
+               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;
@@ -836,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
@@ -870,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,
@@ -914,6 +915,8 @@ 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>"),
@@ -921,7 +924,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                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]"),
+                  "             [--textconv | --filters] [-Z]"),
                N_("git cat-file (--textconv | --filters)\n"
                   "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
                NULL
@@ -950,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,
@@ -1009,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 d7a40e674ca049e414d1443b2e5a78d85c392ab2..b22ff748c3e20819887084f1175015a9a6078815 100644 (file)
@@ -1,10 +1,15 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "attr.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
 #include "quote.h"
+#include "repository.h"
+#include "setup.h"
 #include "parse-options.h"
+#include "write-or-die.h"
 
 static int all_attrs;
 static int cached_attrs;
@@ -58,7 +63,7 @@ static void output_attr(struct attr_check *check, const char *file)
 }
 
 static void check_attr(const char *prefix, struct attr_check *check,
-                      const struct object_id *tree_oid, int collect_all,
+                      int collect_all,
                       const char *file)
 
 {
@@ -66,9 +71,9 @@ static void check_attr(const char *prefix, struct attr_check *check,
                prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
 
        if (collect_all) {
-               git_all_attrs(&the_index, tree_oid, full_path, check);
+               git_all_attrs(&the_index, full_path, check);
        } else {
-               git_check_attr(&the_index, tree_oid, full_path, check);
+               git_check_attr(&the_index, full_path, check);
        }
        output_attr(check, file);
 
@@ -76,7 +81,7 @@ static void check_attr(const char *prefix, struct attr_check *check,
 }
 
 static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
-                                  const struct object_id *tree_oid, int collect_all)
+                                  int collect_all)
 {
        struct strbuf buf = STRBUF_INIT;
        struct strbuf unquoted = STRBUF_INIT;
@@ -90,7 +95,7 @@ static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
                                die("line is badly quoted");
                        strbuf_swap(&buf, &unquoted);
                }
-               check_attr(prefix, check, tree_oid, collect_all, buf.buf);
+               check_attr(prefix, check, collect_all, buf.buf);
                maybe_flush_or_die(stdout, "attribute to stdout");
        }
        strbuf_release(&buf);
@@ -106,7 +111,6 @@ static NORETURN void error_with_usage(const char *msg)
 int cmd_check_attr(int argc, const char **argv, const char *prefix)
 {
        struct attr_check *check;
-       struct object_id *tree_oid = NULL;
        struct object_id initialized_oid;
        int cnt, i, doubledash, filei;
 
@@ -182,14 +186,14 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
        if (source) {
                if (repo_get_oid_tree(the_repository, source, &initialized_oid))
                        die("%s: not a valid tree-ish source", source);
-               tree_oid = &initialized_oid;
+               set_git_attr_source(source);
        }
 
        if (stdin_paths)
-               check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
+               check_attr_stdin_paths(prefix, check, all_attrs);
        else {
                for (i = filei; i < argc; i++)
-                       check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
+                       check_attr(prefix, check, all_attrs, argv[i]);
                maybe_flush_or_die(stdout, "attribute to stdout");
        }
 
index ab776061c7c4f2e1f53c3408a323db3dac6bc440..906cd967536c6f3a90c0a57cb4f3649e7b0da804 100644 (file)
@@ -1,12 +1,14 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
+#include "gettext.h"
 #include "quote.h"
 #include "pathspec.h"
 #include "parse-options.h"
+#include "repository.h"
 #include "submodule.h"
+#include "write-or-die.h"
 
 static int quiet, verbose, stdin_paths, show_non_matching, no_index;
 static const char * const check_ignore_usage[] = {
index 7dc47e47932c7d2e76128e54f49fa2ea0c570d62..b8a05b8e07b523953dfe9e8d6e572346a27d7791 100644 (file)
@@ -1,8 +1,12 @@
 #include "builtin.h"
 #include "config.h"
+#include "gettext.h"
+#include "ident.h"
 #include "mailmap.h"
 #include "parse-options.h"
+#include "strbuf.h"
 #include "string-list.h"
+#include "write-or-die.h"
 
 static int use_stdin;
 static const char * const check_mailmap_usage[] = {
index fd0e5f86832a0ed4d9c08512291c836938f2bec2..5eb6bdc3f691e8a71e07fc2be80ee94e3599f522 100644 (file)
@@ -2,9 +2,9 @@
  * GIT - The information manager from hell
  */
 
-#include "cache.h"
-#include "refs.h"
 #include "builtin.h"
+#include "refs.h"
+#include "setup.h"
 #include "strbuf.h"
 
 static const char builtin_check_ref_format_usage[] =
@@ -60,6 +60,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
        char *to_free = NULL;
        int ret = 1;
 
+       BUG_ON_NON_EMPTY_PREFIX(prefix);
+
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(builtin_check_ref_format_usage);
 
index ede7dc32a43c01a78a0074e1bddd5ba18b487568..6b62b5375bd2bf0d998f74ba2c63c071a5e76e73 100644 (file)
@@ -1,9 +1,11 @@
 #include "builtin.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 cf6fba97ba784a201b8becff88cc82eac93cf7f7..f62f13f2b5324e15f982071f73b24281d2d9637a 100644 (file)
@@ -8,12 +8,17 @@
 #include "builtin.h"
 #include "config.h"
 #include "dir.h"
+#include "gettext.h"
 #include "lockfile.h"
 #include "quote.h"
+#include "repository.h"
 #include "cache-tree.h"
 #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;
index a5155cf55c1e5150fd954a5b59363ee899974361..f53612f46870529e87cec15a2f7233c74e4b173d 100644 (file)
@@ -9,19 +9,30 @@
 #include "config.h"
 #include "diff.h"
 #include "dir.h"
+#include "environment.h"
+#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-store.h"
+#include "object-name.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"
 #include "revision.h"
 #include "run-command.h"
+#include "setup.h"
 #include "submodule.h"
 #include "submodule-config.h"
+#include "symlinks.h"
+#include "trace2.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
@@ -75,7 +86,7 @@ struct checkout_opts {
        const char *ignore_unmerged_opt;
        int ignore_unmerged;
        int pathspec_file_nul;
-       const char *pathspec_from_file;
+       char *pathspec_from_file;
 
        const char *new_branch;
        const char *new_branch_force;
@@ -432,8 +443,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
                                              "Updated %d paths from %s",
                                              nr_checkouts),
                                   nr_checkouts,
-                                  find_unique_abbrev(&opts->source_tree->object.oid,
-                                                     DEFAULT_ABBREV));
+                                  repo_find_unique_abbrev(the_repository, &opts->source_tree->object.oid,
+                                                          DEFAULT_ABBREV));
                else if (!nr_unmerged || nr_checkouts)
                        fprintf_ln(stderr, Q_("Updated %d path from the index",
                                              "Updated %d paths from the index",
@@ -489,15 +500,28 @@ static int checkout_paths(const struct checkout_opts *opts,
                die(_("'%s' must be used when '%s' is not specified"),
                    "--worktree", "--source");
 
-       if (opts->checkout_index && !opts->checkout_worktree &&
-           opts->writeout_stage)
-               die(_("'%s' or '%s' cannot be used with %s"),
-                   "--ours", "--theirs", "--staged");
-
-       if (opts->checkout_index && !opts->checkout_worktree &&
-           opts->merge)
-               die(_("'%s' or '%s' cannot be used with %s"),
-                   "--merge", "--conflict", "--staged");
+       /*
+        * Reject --staged option to the restore command when combined with
+        * merge-related options. Use the accept_ref flag to distinguish it
+        * from the checkout command, which does not accept --staged anyway.
+        *
+        * `restore --ours|--theirs --worktree --staged` could mean resolving
+        * conflicted paths to one side in both the worktree and the index,
+        * but does not currently.
+        *
+        * `restore --merge|--conflict=<style>` already recreates conflicts
+        * in both the worktree and the index, so adding --staged would be
+        * meaningless.
+        */
+       if (!opts->accept_ref && opts->checkout_index) {
+               if (opts->writeout_stage)
+                       die(_("'%s' or '%s' cannot be used with %s"),
+                           "--ours", "--theirs", "--staged");
+
+               if (opts->merge)
+                       die(_("'%s' or '%s' cannot be used with %s"),
+                           "--merge", "--conflict", "--staged");
+       }
 
        if (opts->patch_mode) {
                enum add_p_mode patch_mode;
@@ -640,14 +664,16 @@ static void describe_detached_head(const char *msg, struct commit *commit)
 {
        struct strbuf sb = STRBUF_INIT;
 
-       if (!parse_commit(commit))
+       if (!repo_parse_commit(the_repository, commit))
                pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
        if (print_sha1_ellipsis()) {
                fprintf(stderr, "%s %s... %s\n", msg,
-                       find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
+                       repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+                       sb.buf);
        } else {
                fprintf(stderr, "%s %s %s\n", msg,
-                       find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
+                       repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+                       sb.buf);
        }
        strbuf_release(&sb);
 }
@@ -701,7 +727,8 @@ static void setup_branch_path(struct branch_info *branch)
         * If this is a ref, resolve it; otherwise, look up the OID for our
         * expression.  Failure here is okay.
         */
-       if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname, 0))
+       if (!repo_dwim_ref(the_repository, branch->name, strlen(branch->name),
+                          &branch->oid, &branch->refname, 0))
                repo_get_oid_committish(the_repository, branch->name, &branch->oid);
 
        strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
@@ -753,7 +780,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
                        BUG("'switch --orphan' should never accept a commit as starting point");
                new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
        } else
-               new_tree = get_commit_tree(new_branch_info->commit);
+               new_tree = repo_get_commit_tree(the_repository,
+                                               new_branch_info->commit);
        if (opts->discard_changes) {
                ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
                if (ret)
@@ -815,7 +843,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
                         */
                        if (!old_branch_info->commit)
                                return 1;
-                       old_tree = get_commit_tree(old_branch_info->commit);
+                       old_tree = repo_get_commit_tree(the_repository,
+                                                       old_branch_info->commit);
 
                        if (repo_index_has_changes(the_repository, old_tree, &sb))
                                die(_("cannot continue with staged changes in "
@@ -835,7 +864,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);
@@ -887,7 +916,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);
@@ -1004,7 +1033,7 @@ static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
        strbuf_addstr(sb, "  ");
        strbuf_add_unique_abbrev(sb, &commit->object.oid, DEFAULT_ABBREV);
        strbuf_addch(sb, ' ');
-       if (!parse_commit(commit))
+       if (!repo_parse_commit(the_repository, commit))
                pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
        strbuf_addch(sb, '\n');
 }
@@ -1060,7 +1089,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
                        " git branch <new-branch-name> %s\n\n",
                        /* Give ngettext() the count */
                        lost),
-                       find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+                       repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
 }
 
 /*
@@ -1160,7 +1189,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;
 
@@ -1176,7 +1206,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(
@@ -1204,7 +1234,8 @@ static void setup_new_branch_info_and_source_tree(
                *source_tree = parse_tree_indirect(rev);
        } else {
                parse_commit_or_die(new_branch_info->commit);
-               *source_tree = get_commit_tree(new_branch_info->commit);
+               *source_tree = repo_get_commit_tree(the_repository,
+                                                   new_branch_info->commit);
        }
 }
 
@@ -1322,7 +1353,7 @@ static int parse_branchname_arg(int argc, const char **argv,
        if (!strcmp(arg, "-"))
                arg = "@{-1}";
 
-       if (get_oid_mb(arg, rev)) {
+       if (repo_get_oid_mb(the_repository, arg, rev)) {
                /*
                 * Either case (3) or (4), with <something> not being
                 * a commit, or an attempt to use case (1) with an
@@ -1419,7 +1450,8 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
        char *to_free;
        int code;
 
-       if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
+       if (repo_dwim_ref(the_repository, branch_info->name,
+                         strlen(branch_info->name), &oid, &to_free, 0) == 1) {
                const char *ref = to_free;
 
                if (skip_prefix(ref, "refs/tags/", &ref))
@@ -1661,8 +1693,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;
@@ -1748,7 +1785,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
        } else if (!opts->accept_ref && opts->from_treeish) {
                struct object_id rev;
 
-               if (get_oid_mb(opts->from_treeish, &rev))
+               if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
                        die(_("could not resolve %s"), opts->from_treeish);
 
                setup_new_branch_info_and_source_tree(new_branch_info,
@@ -1876,6 +1913,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                            options, checkout_usage, &new_branch_info);
        branch_info_release(&new_branch_info);
        clear_pathspec(&opts.pathspec);
+       free(opts.pathspec_from_file);
        FREE_AND_NULL(options);
        return ret;
 }
index 10aaa8c603fe587682724531bbdbfc92de80a79c..49c224e626d61819a633252572d3e7f3b32ffd62 100644 (file)
@@ -8,10 +8,15 @@
 
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
+#include "abspath.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"
 #include "quote.h"
 #include "column.h"
@@ -99,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;
 
@@ -126,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 65b5b7db6de5bdac835ad95b6438c1cc548d1599..c6357af949895a688639c83984598931906b2690 100644 (file)
 
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
 #include "config.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "fetch-pack.h"
 #include "refs.h"
 #include "refspec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
 #include "branch.h"
 #include "remote.h"
 #include "run-command.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"
@@ -151,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")),
@@ -326,8 +333,18 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
 
        iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
 
-       if (!iter)
+       if (!iter) {
+               if (errno == ENOTDIR) {
+                       int saved_errno = errno;
+                       struct stat st;
+
+                       if (!lstat(src->buf, &st) && S_ISLNK(st.st_mode))
+                               die(_("'%s' is a symlink, refusing to clone with --local"),
+                                   src->buf);
+                       errno = saved_errno;
+               }
                die_errno(_("failed to start iterator over '%s'"), src->buf);
+       }
 
        strbuf_addch(src, '/');
        src_len = src->len;
@@ -547,9 +564,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
                        continue;
                if (ends_with(ref->name, "^{}"))
                        continue;
-               if (!has_object_file_with_flags(&ref->old_oid,
-                                               OBJECT_INFO_QUICK |
-                                               OBJECT_INFO_SKIP_FETCH_OBJECT))
+               if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid,
+                                                    OBJECT_INFO_QUICK |
+                                                    OBJECT_INFO_SKIP_FETCH_OBJECT))
                        continue;
                update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
                           UPDATE_REFS_DIE_ON_ERR);
@@ -770,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);
@@ -781,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;
 
@@ -909,6 +929,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        int err = 0, complete_refs_before_fetch = 1;
        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;
@@ -1076,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);
@@ -1297,15 +1319,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                }
        }
 
-       if (mapped_refs) {
-               int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
-
                /*
                 * Now that we know what algorithm the remote side is using,
                 * let's set ours to the same thing.
                 */
-               initialize_repository_version(hash_algo, 1);
-               repo_set_hash_algo(the_repository, hash_algo);
+       hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+       initialize_repository_version(hash_algo, 1);
+       repo_set_hash_algo(the_repository, hash_algo);
+
+       if (mapped_refs) {
                /*
                 * transport_get_remote_refs() may return refs with null sha-1
                 * in mapped_refs (see struct transport->get_refs_list
index 158fdf53d9fb9ce3694502fe6edbc609d7839282..a83be8bc991a8c9dfca5b64f886d33f952890236 100644 (file)
@@ -1,6 +1,6 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
+#include "gettext.h"
 #include "strbuf.h"
 #include "parse-options.h"
 #include "string-list.h"
@@ -12,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 93704f95a9da8ab8313e7a17589153951e3bb9fe..c88389df24ed5cb552ca22a4be0e29c625a9ac23 100644 (file)
@@ -1,13 +1,19 @@
 #include "builtin.h"
+#include "commit.h"
 #include "config.h"
 #include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #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"
+#include "trace2.h"
 
 #define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \
        N_("git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]")
@@ -181,10 +187,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()'.
@@ -319,7 +326,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 cc8d584be2f4a9d3b0c950a4b8cbc6c140904d8c..02625e71761dbf8d25f063b5ff4835e5eb4bf477 100644 (file)
@@ -3,13 +3,15 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.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"
@@ -37,14 +39,6 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
        commit_list_insert(parent, parents_p);
 }
 
-static int commit_tree_config(const char *var, const char *value, void *cb)
-{
-       int status = git_gpg_config(var, value, NULL);
-       if (status)
-               return status;
-       return git_default_config(var, value, cb);
-}
-
 static int parse_parent_arg_callback(const struct option *opt,
                const char *arg, int unset)
 {
@@ -53,7 +47,7 @@ static int parse_parent_arg_callback(const struct option *opt,
 
        BUG_ON_OPT_NEG_NOARG(unset, arg);
 
-       if (get_oid_commit(arg, &oid))
+       if (repo_get_oid_commit(the_repository, arg, &oid))
                die(_("not a valid object name %s"), arg);
 
        assert_oid_type(&oid, OBJ_COMMIT);
@@ -121,7 +115,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
-       git_config(commit_tree_config, NULL);
+       git_config(git_default_config, NULL);
 
        if (argc < 2 || !strcmp(argv[1], "-h"))
                usage_with_options(commit_tree_usage, options);
@@ -131,7 +125,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
        if (argc != 1)
                die(_("must give exactly one tree"));
 
-       if (get_oid_tree(argv[0], &tree_oid))
+       if (repo_get_oid_tree(the_repository, argv[0], &tree_oid))
                die(_("not a valid object name %s"), argv[0]);
 
        if (!buffer.len) {
index 985a0445b7897c936cc69e828d1e9f4ad98abaf7..7da5f924484d586c765796f8e411a042f2a3817a 100644 (file)
@@ -6,16 +6,19 @@
  */
 
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
 #include "config.h"
 #include "lockfile.h"
 #include "cache-tree.h"
 #include "color.h"
 #include "dir.h"
-#include "builtin.h"
+#include "editor.h"
+#include "environment.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "commit.h"
+#include "gettext.h"
 #include "revision.h"
 #include "wt-status.h"
 #include "run-command.h"
 #include "log-tree.h"
 #include "strbuf.h"
 #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"
@@ -33,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"
@@ -442,7 +450,8 @@ 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))
@@ -557,7 +566,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
        s->index_file = index_file;
        s->fp = fp;
        s->nowarn = nowarn;
-       s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
+       s->is_initial = repo_get_oid(the_repository, s->reference, &oid) ? 1 : 0;
        if (!s->is_initial)
                oidcpy(&s->oid_commit, &oid);
        s->status_format = status_format;
@@ -712,15 +721,15 @@ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
 {
        const char *buffer, *subject, *fmt;
 
-       buffer = get_commit_buffer(commit, NULL);
+       buffer = repo_get_commit_buffer(the_repository, commit, NULL);
        find_commit_subject(buffer, &subject);
        /*
         * If we amend the 'amend!' commit then we don't want to
         * duplicate the subject line.
         */
        fmt = starts_with(subject, "amend!") ? "%b" : "%B";
-       format_commit_message(commit, fmt, sb, ctx);
-       unuse_commit_buffer(commit, buffer);
+       repo_format_commit_message(the_repository, commit, fmt, sb, ctx);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
 }
 
 static int prepare_to_commit(const char *index_file, const char *prefix,
@@ -758,10 +767,11 @@ 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();
-                       format_commit_message(c, "squash! %s\n\n", &sb,
-                                             &ctx);
+                       repo_format_commit_message(the_repository, c,
+                                                  "squash! %s\n\n", &sb,
+                                                  &ctx);
                }
        }
 
@@ -792,10 +802,11 @@ 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);
-               format_commit_message(commit, fmt, &sb, &ctx);
+               repo_format_commit_message(the_repository, commit, fmt, &sb,
+                                          &ctx);
                free(fmt);
                hook_arg1 = "message";
 
@@ -886,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);
@@ -991,16 +1002,13 @@ 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";
 
-               if (get_oid(parent, &oid)) {
+               if (repo_get_oid(the_repository, parent, &oid)) {
                        int i, ita_nr = 0;
 
                        /* TODO: audit for interaction with sparse-index. */
@@ -1036,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))
@@ -1135,7 +1144,8 @@ static const char *find_author_by_nickname(const char *name)
                struct pretty_print_context ctx = {0};
                ctx.date_mode.type = DATE_NORMAL;
                strbuf_release(&buf);
-               format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
+               repo_format_commit_message(the_repository, commit,
+                                          "%aN <%aE>", &buf, &ctx);
                release_revisions(&revs);
                return strbuf_detach(&buf, NULL);
        }
@@ -1181,9 +1191,9 @@ 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 logmsg_reencode(commit, NULL, out_enc);
+       return repo_logmsg_reencode(the_repository, commit, NULL, out_enc);
 }
 
 /*
@@ -1397,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;
@@ -1406,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;
@@ -1466,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")) {
@@ -1482,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)
@@ -1567,7 +1579,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        else
                fd = -1;
 
-       s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
+       s.is_initial = repo_get_oid(the_repository, s.reference, &oid) ? 1 : 0;
        if (!s.is_initial)
                oidcpy(&s.oid_commit, &oid);
 
@@ -1597,10 +1609,10 @@ 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;
-       int status;
 
        if (!strcmp(k, "commit.template"))
                return git_config_pathname(&template_file, k, v);
@@ -1616,14 +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;
        }
 
-       status = git_gpg_config(k, v, NULL);
-       if (status)
-               return status;
-       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)
@@ -1714,11 +1724,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
        s.colopts = 0;
 
-       if (get_oid("HEAD", &oid))
+       if (repo_get_oid(the_repository, "HEAD", &oid))
                current_head = NULL;
        else {
                current_head = lookup_commit_or_die(&oid, "HEAD");
-               if (parse_commit(current_head))
+               if (repo_parse_commit(the_repository, current_head))
                        die(_("could not parse HEAD commit"));
        }
        verbose = -1; /* unspecified */
index 060cf9f3e05e6718ae02923e132e4804dbdcb291..11a4d4ef1411222f3750c760b68efd10180148c0 100644 (file)
@@ -1,10 +1,18 @@
 #include "builtin.h"
-#include "cache.h"
+#include "abspath.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"
 #include "urlmatch.h"
+#include "path.h"
 #include "quote.h"
+#include "setup.h"
+#include "strbuf.h"
 #include "worktree.h"
 
 static const char *const builtin_config_usage[] = {
@@ -185,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);
@@ -233,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) {
@@ -247,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
@@ -292,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;
@@ -309,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)
@@ -367,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);
        }
@@ -403,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;
@@ -418,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
@@ -460,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)) {
@@ -478,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)
@@ -492,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))
@@ -510,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"))
@@ -547,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));
@@ -562,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);
@@ -599,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;
 
@@ -608,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);
 
@@ -642,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));
 
@@ -705,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 "
@@ -819,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'"),
@@ -859,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"
@@ -868,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);
@@ -876,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,
@@ -885,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 07b941959628b9d02dbf0282e779040cea5b27be..2d4bb5e8d0a8dfce1290760f7cd99dac7ba39a3e 100644 (file)
@@ -4,15 +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;
@@ -57,7 +59,8 @@ static void loose_garbage(const char *path)
                report_garbage(PACKDIR_FILE_GARBAGE, path);
 }
 
-static int count_loose(const struct object_id *oid, const char *path, void *data)
+static int count_loose(const struct object_id *oid, const char *path,
+                      void *data UNUSED)
 {
        struct stat st;
 
@@ -72,13 +75,14 @@ static int count_loose(const struct object_id *oid, const char *path, void *data
        return 0;
 }
 
-static int count_cruft(const char *basename, const char *path, void *data)
+static int count_cruft(const char *basename UNUSED, const char *path,
+                      void *data UNUSED)
 {
        loose_garbage(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 338058be7f943759619965911a7ad18f19263e48..3a6a750a8eb320bb3622184843ede3d2b9884385 100644 (file)
@@ -1,4 +1,7 @@
 #include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
 #include "parse-options.h"
 
 #ifndef NO_UNIX_SOCKETS
@@ -34,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)
@@ -130,6 +136,9 @@ static void serve_one_client(FILE *in, FILE *out)
                        if (e->item.password_expiry_utc != TIME_MAX)
                                fprintf(out, "password_expiry_utc=%"PRItime"\n",
                                        e->item.password_expiry_utc);
+                       if (e->item.oauth_refresh_token)
+                               fprintf(out, "oauth_refresh_token=%s\n",
+                                       e->item.oauth_refresh_token);
                }
        }
        else if (!strcmp(action.buf, "exit")) {
@@ -144,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 78c02ad53192323e8237a3b0555b4f4f1b4dbceb..43b9d0e5b16ba5da555a3b16ce53b88dff5dbb4c 100644 (file)
@@ -1,5 +1,9 @@
 #include "builtin.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "path.h"
+#include "strbuf.h"
+#include "write-or-die.h"
 
 #ifndef NO_UNIX_SOCKETS
 
index 62a4f3c26531432da689dabe38b724c6e5484c7d..4a492411bbf3d2a7f0a34ada0bd127ae97cf5552 100644 (file)
@@ -1,16 +1,20 @@
 #include "builtin.h"
 #include "config.h"
+#include "gettext.h"
 #include "lockfile.h"
 #include "credential.h"
+#include "path.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "write-or-die.h"
 
 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;
@@ -27,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);
@@ -57,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;
 
@@ -66,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;
@@ -88,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);
 }
 
@@ -135,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)
@@ -143,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 d7b304fa084fd6c714ce9a6853d903ae6636bb33..70107529876372c693fa15bbf6aff54ca63b4ce7 100644 (file)
@@ -6,7 +6,7 @@
 static const char usage_msg[] =
        "git credential (fill|approve|reject)";
 
-int cmd_credential(int argc, const char **argv, const char *prefix)
+int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
 {
        const char *op;
        struct credential c = CREDENTIAL_INIT;
index eea1e330c00c62a649b5a059bbfcf6e351f95269..a9e375882bf2545736b2d38e65bc744c7d7b3497 100644 (file)
@@ -1,24 +1,31 @@
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "commit.h"
 #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 *);
 
@@ -35,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;
@@ -261,7 +268,7 @@ static unsigned long finish_depth_computation(
                        best->depth++;
                while (parents) {
                        struct commit *p = parents->item;
-                       parse_commit(p);
+                       repo_parse_commit(the_repository, p);
                        if (!(p->object.flags & SEEN))
                                commit_list_insert_by_date(p, list);
                        p->object.flags |= c->object.flags;
@@ -298,7 +305,8 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
 
 static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
 {
-       strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid, abbrev));
+       strbuf_addf(dst, "-%d-g%s", depth,
+                   repo_find_unique_abbrev(the_repository, oid, abbrev));
 }
 
 static void describe_commit(struct object_id *oid, struct strbuf *dst)
@@ -403,7 +411,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
                }
                while (parents) {
                        struct commit *p = parents->item;
-                       parse_commit(p);
+                       repo_parse_commit(the_repository, p);
                        if (!(p->object.flags & SEEN))
                                commit_list_insert_by_date(p, &list);
                        p->object.flags |= c->object.flags;
@@ -531,7 +539,7 @@ static void describe(const char *arg, int last_one)
        if (debug)
                fprintf(stderr, _("describe %s\n"), arg);
 
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                die(_("Not a valid object name %s"), arg);
        cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
 
@@ -550,6 +558,15 @@ 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)
+{
+       BUG_ON_OPT_ARG(arg);
+
+       max_candidates = unset ? DEFAULT_CANDIDATES : 0;
+       return 0;
+}
+
 int cmd_describe(int argc, const char **argv, const char *prefix)
 {
        int contains = 0;
@@ -561,8 +578,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", NULL, 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"),
@@ -650,9 +668,11 @@ 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);
+                       the_repository->settings.command_requires_full_index = 0;
                        repo_read_index(the_repository);
                        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
                                      NULL, NULL, NULL);
@@ -665,9 +685,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 d52015c67a411f0c5694680136728d678fea05af..4f22eb2b55d06968896d12ae9257d470d5d3a8fb 100644 (file)
@@ -1,4 +1,7 @@
 #include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
 #include "parse-options.h"
 #include "diagnose.h"
 
index dc991f753bb8f10b2414a9c3486f8374d388f82a..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[] =
@@ -27,6 +28,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
                usage(diff_files_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, &rev, prefix);
        rev.abbrev = 0;
 
@@ -75,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 35dc9b23eef32d81e1e0a1b42a810ca6d95f58a2..220f341ffa2a138f70d6aa0d343594e6e60d2ebb 100644 (file)
@@ -1,10 +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[] =
@@ -69,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 25b853b85ca99d210d230d6783b824a270de9d6c..86be6342861be40da9edbf2f1a2002fa4abc0cda 100644 (file)
@@ -1,12 +1,16 @@
 #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;
 
@@ -95,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)
@@ -119,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"));
@@ -224,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 26f1e532c66b173fb4b29d220564fcd90c03d0d2..0b313549c764b7dc0d001b0b793fc160b04059ac 100644 (file)
@@ -4,22 +4,26 @@
  * 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 "color.h"
 #include "commit.h"
 #include "blob.h"
+#include "gettext.h"
 #include "tag.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"
+#include "tree.h"
 
 #define DIFF_NO_INDEX_EXPLICIT 1
 #define DIFF_NO_INDEX_IMPLICIT 2
@@ -73,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,
-                           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;
@@ -105,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,
-                             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);
 
@@ -130,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) {
@@ -159,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;
@@ -205,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,
-                                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;
@@ -232,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)
@@ -250,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;
 
@@ -265,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--;
        }
 
@@ -283,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 {
@@ -400,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;
 
        /*
@@ -548,7 +547,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                if (!obj)
                        die(_("invalid object '%s' given."), name);
                if (obj->type == OBJ_COMMIT)
-                       obj = &get_commit_tree(((struct commit *)obj))->object;
+                       obj = &repo_get_commit_tree(the_repository,
+                                                   ((struct commit *)obj))->object;
 
                if (obj->type == OBJ_TREE) {
                        if (sdiff.skip && bitmap_get(sdiff.skip, i))
@@ -578,17 +578,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);
@@ -597,18 +597,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 dbbfb19f1921028f78b499af0ad35a67c9595d59..0f5eae9cd41b3219b06964011089bb8d389975b4 100644 (file)
  * Copyright (C) 2016 Johannes Schindelin
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "copy.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-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "dir.h"
 #include "entry.h"
+#include "setup.h"
 
 static int trust_exit_code;
 
@@ -32,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)
@@ -295,7 +304,8 @@ static char *get_symlink(const struct object_id *oid, const char *path)
        } else {
                enum object_type type;
                unsigned long size;
-               data = read_object_file(oid, &type, &size);
+               data = repo_read_object_file(the_repository, oid, &type,
+                                            &size);
                if (!data)
                        die(_("could not read object %s for symlink %s"),
                                oid_to_hex(oid), path);
@@ -684,7 +694,7 @@ static int run_file_diff(int prompt, const char *prefix,
 
 int cmd_difftool(int argc, const char **argv, const char *prefix)
 {
-       int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
+       int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
            tool_help = 0, no_index = 0;
        static char *difftool_cmd = NULL, *extcmd = NULL;
        struct option builtin_difftool_options[] = {
@@ -734,13 +744,21 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
        } else if (dir_diff)
                die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
 
-       die_for_incompatible_opt3(use_gui_tool, "--gui",
+       die_for_incompatible_opt3(use_gui_tool == 1, "--gui",
                                  !!difftool_cmd, "--tool",
                                  !!extcmd, "--extcmd");
 
-       if (use_gui_tool)
+       /*
+        * Explicitly specified GUI option is forwarded to git-mergetool--lib.sh;
+        * empty or unset means "use the difftool.guiDefault config or default to
+        * false".
+        */
+       if (use_gui_tool == 1)
                setenv("GIT_MERGETOOL_GUI", "true", 1);
-       else if (difftool_cmd) {
+       else if (use_gui_tool == 0)
+               setenv("GIT_MERGETOOL_GUI", "false", 1);
+
+       if (difftool_cmd) {
                if (*difftool_cmd)
                        setenv("GIT_DIFF_TOOL", difftool_cmd, 1);
                else
index 39a890fc005192a5082a1c170550f4be102efbc1..56dc69fac180126a43f8a9ca3ed116ca67283737 100644 (file)
@@ -4,11 +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-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "object.h"
 #include "tag.h"
@@ -109,7 +111,7 @@ static struct decoration idnums;
 static uint32_t last_idnum;
 struct anonymized_entry {
        struct hashmap_entry hash;
-       const char *anon;
+       char *anon;
        const char orig[FLEX_ARRAY];
 };
 
@@ -138,43 +140,56 @@ static int anonymized_entry_cmp(const void *cmp_data UNUSED,
        return strcmp(a->orig, b->orig);
 }
 
+static struct anonymized_entry *add_anonymized_entry(struct hashmap *map,
+                                                    unsigned hash,
+                                                    const char *orig, size_t len,
+                                                    char *anon)
+{
+       struct anonymized_entry *ret, *old;
+
+       if (!map->cmpfn)
+               hashmap_init(map, anonymized_entry_cmp, NULL, 0);
+
+       FLEX_ALLOC_MEM(ret, orig, orig, len);
+       hashmap_entry_init(&ret->hash, hash);
+       ret->anon = anon;
+       old = hashmap_put_entry(map, ret, hash);
+
+       if (old) {
+               free(old->anon);
+               free(old);
+       }
+
+       return ret;
+}
+
 /*
  * Basically keep a cache of X->Y so that we can repeatedly replace
  * the same anonymized string with another. The actual generation
  * is farmed out to the generate function.
  */
 static const char *anonymize_str(struct hashmap *map,
-                                char *(*generate)(void *),
-                                const char *orig, size_t len,
-                                void *data)
+                                char *(*generate)(void),
+                                const char *orig, size_t len)
 {
        struct anonymized_entry_key key;
        struct anonymized_entry *ret;
 
-       if (!map->cmpfn)
-               hashmap_init(map, anonymized_entry_cmp, NULL, 0);
-
        hashmap_entry_init(&key.hash, memhash(orig, len));
        key.orig = orig;
        key.orig_len = len;
 
        /* First check if it's a token the user configured manually... */
-       if (anonymized_seeds.cmpfn)
-               ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
-       else
-               ret = NULL;
+       ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
 
        /* ...otherwise check if we've already seen it in this context... */
        if (!ret)
                ret = hashmap_get_entry(map, &key, hash, &key);
 
        /* ...and finally generate a new mapping if necessary */
-       if (!ret) {
-               FLEX_ALLOC_MEM(ret, orig, orig, len);
-               hashmap_entry_init(&ret->hash, key.hash.hash);
-               ret->anon = generate(data);
-               hashmap_put(map, &ret->hash);
-       }
+       if (!ret)
+               ret = add_anonymized_entry(map, key.hash.hash,
+                                          orig, len, generate());
 
        return ret->anon;
 }
@@ -187,12 +202,12 @@ static const char *anonymize_str(struct hashmap *map,
  */
 static void anonymize_path(struct strbuf *out, const char *path,
                           struct hashmap *map,
-                          char *(*generate)(void *))
+                          char *(*generate)(void))
 {
        while (*path) {
                const char *end_of_component = strchrnul(path, '/');
                size_t len = end_of_component - path;
-               const char *c = anonymize_str(map, generate, path, len, NULL);
+               const char *c = anonymize_str(map, generate, path, len);
                strbuf_addstr(out, c);
                path = end_of_component;
                if (*path)
@@ -296,7 +311,7 @@ static void export_blob(const struct object_id *oid)
                object = (struct object *)lookup_blob(the_repository, oid);
                eaten = 0;
        } else {
-               buf = read_object_file(oid, &type, &size);
+               buf = repo_read_object_file(the_repository, oid, &type, &size);
                if (!buf)
                        die("could not read blob %s", oid_to_hex(oid));
                if (check_object_signature(the_repository, oid, buf, size,
@@ -367,7 +382,7 @@ static void print_path_1(const char *path)
                printf("%s", path);
 }
 
-static char *anonymize_path_component(void *data)
+static char *anonymize_path_component(void)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
@@ -389,7 +404,7 @@ static void print_path(const char *path)
        }
 }
 
-static char *generate_fake_oid(void *data)
+static char *generate_fake_oid(void)
 {
        static uint32_t counter = 1; /* avoid null oid */
        const unsigned hashsz = the_hash_algo->rawsz;
@@ -405,7 +420,7 @@ static const char *anonymize_oid(const char *oid_hex)
 {
        static struct hashmap objs;
        size_t len = strlen(oid_hex);
-       return anonymize_str(&objs, generate_fake_oid, oid_hex, len, NULL);
+       return anonymize_str(&objs, generate_fake_oid, oid_hex, len);
 }
 
 static void show_filemodify(struct diff_queue_struct *q,
@@ -502,7 +517,7 @@ static const char *find_encoding(const char *begin, const char *end)
        return bol;
 }
 
-static char *anonymize_ref_component(void *data)
+static char *anonymize_ref_component(void)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
@@ -542,13 +557,13 @@ static const char *anonymize_refname(const char *refname)
  * We do not even bother to cache commit messages, as they are unlikely
  * to be repeated verbatim, and it is not that interesting when they are.
  */
-static char *anonymize_commit_message(const char *old)
+static char *anonymize_commit_message(void)
 {
        static int counter;
        return xstrfmt("subject %d\n\nbody\n", counter++);
 }
 
-static char *anonymize_ident(void *data)
+static char *anonymize_ident(void)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
@@ -591,7 +606,7 @@ static void anonymize_ident_line(const char **beg, const char **end)
 
                len = split.mail_end - split.name_begin;
                ident = anonymize_str(&idents, anonymize_ident,
-                                     split.name_begin, len, NULL);
+                                     split.name_begin, len);
                strbuf_addstr(out, ident);
                strbuf_addch(out, ' ');
                strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
@@ -618,7 +633,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
        rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
 
        parse_commit_or_die(commit);
-       commit_buffer = get_commit_buffer(commit, NULL);
+       commit_buffer = repo_get_commit_buffer(the_repository, commit, NULL);
        author = strstr(commit_buffer, "\nauthor ");
        if (!author)
                die("could not find author in commit %s",
@@ -669,7 +684,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
 
        mark_next_object(&commit->object);
        if (anonymize) {
-               reencoded = anonymize_commit_message(message);
+               reencoded = anonymize_commit_message();
        } else if (encoding) {
                switch(reencode_mode) {
                case REENCODE_YES:
@@ -699,7 +714,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
                          ? strlen(message) : 0),
               reencoded ? reencoded : message ? message : "");
        free(reencoded);
-       unuse_commit_buffer(commit, commit_buffer);
+       repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
 
        for (i = 0, p = commit->parents; p; p = p->next) {
                struct object *obj = &p->item->object;
@@ -732,7 +747,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
        show_progress();
 }
 
-static char *anonymize_tag(void *data)
+static char *anonymize_tag(void)
 {
        static int counter;
        struct strbuf out = STRBUF_INIT;
@@ -766,7 +781,8 @@ static void handle_tag(const char *name, struct tag *tag)
                return;
        }
 
-       buf = read_object_file(&tag->object.oid, &type, &size);
+       buf = repo_read_object_file(the_repository, &tag->object.oid, &type,
+                                   &size);
        if (!buf)
                die("could not read tag %s", oid_to_hex(&tag->object.oid));
        message = memmem(buf, size, "\n\n", 2);
@@ -794,7 +810,7 @@ static void handle_tag(const char *name, struct tag *tag)
                if (message) {
                        static struct hashmap tags;
                        message = anonymize_str(&tags, anonymize_tag,
-                                               message, message_size, NULL);
+                                               message, message_size);
                        message_size = strlen(message);
                }
        }
@@ -917,7 +933,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
                if (e->flags & UNINTERESTING)
                        continue;
 
-               if (dwim_ref(e->name, strlen(e->name), &oid, &full_name, 0) != 1)
+               if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+                                 &oid, &full_name, 0) != 1)
                        continue;
 
                if (refspecs.nr) {
@@ -1125,11 +1142,6 @@ static void handle_deletes(void)
        }
 }
 
-static char *anonymize_seed(void *data)
-{
-       return xstrdup(data);
-}
-
 static int parse_opt_anonymize_map(const struct option *opt,
                                   const char *arg, int unset)
 {
@@ -1151,7 +1163,8 @@ static int parse_opt_anonymize_map(const struct option *opt,
        if (!keylen || !*value)
                return error(_("--anonymize-map token cannot be empty"));
 
-       anonymize_str(map, anonymize_seed, arg, keylen, (void *)value);
+       add_anonymized_entry(map, memhash(arg, keylen), arg, keylen,
+                            xstrdup(value));
 
        return 0;
 }
index 7134683ab93f96d4c213d478fc7fadc8a17856c0..4dbb10aff3dacf58b0ecb5daf648cefb16d41f4b 100644 (file)
@@ -1,5 +1,8 @@
 #include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "config.h"
 #include "lockfile.h"
 #include "commit.h"
 #include "delta.h"
 #include "pack.h"
+#include "path.h"
 #include "refs.h"
 #include "csum-file.h"
 #include "quote.h"
 #include "dir.h"
 #include "run-command.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "mem-pool.h"
 #include "commit-reach.h"
 #include "khash.h"
@@ -175,6 +181,7 @@ static FILE *pack_edges;
 static unsigned int show_stats = 1;
 static int global_argc;
 static const char **global_argv;
+static const char *global_prefix;
 
 /* Memory pools */
 static struct mem_pool fi_mem_pool = {
@@ -436,7 +443,7 @@ static void set_checkpoint_signal(void)
 
 #else
 
-static void checkpoint_signal(int signo)
+static void checkpoint_signal(int signo UNUSED)
 {
        checkpoint_requested = 1;
 }
@@ -1265,7 +1272,7 @@ static void load_tree(struct tree_entry *root)
                        die("Can't load tree %s", oid_to_hex(oid));
        } else {
                enum object_type type;
-               buf = read_object_file(oid, &type, &size);
+               buf = repo_read_object_file(the_repository, oid, &type, &size);
                if (!buf || type != OBJ_TREE)
                        die("Can't load tree %s", oid_to_hex(oid));
        }
@@ -1625,7 +1632,7 @@ static int update_branch(struct branch *b)
                if (!old_cmit || !new_cmit)
                        return error("Branch %s is missing commits.", b->name);
 
-               if (!in_merge_bases(old_cmit, new_cmit)) {
+               if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
                                b->name, oid_to_hex(&b->oid),
@@ -2486,7 +2493,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
                if (commit_oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", commit_mark);
                oidcpy(&commit_oid, &commit_oe->idx.oid);
-       } else if (!get_oid(p, &commit_oid)) {
+       } else if (!repo_get_oid(the_repository, p, &commit_oid)) {
                unsigned long size;
                char *buf = read_object_with_reference(the_repository,
                                                       &commit_oid,
@@ -2599,7 +2606,7 @@ static int parse_objectish(struct branch *b, const char *objectish)
                        } else
                                parse_from_existing(b);
                }
-       } else if (!get_oid(objectish, &b->oid)) {
+       } else if (!repo_get_oid(the_repository, objectish, &b->oid)) {
                parse_from_existing(b);
                if (is_null_oid(&b->oid))
                        b->delete = 1;
@@ -2654,7 +2661,7 @@ static struct hash_list *parse_merge(unsigned int *count)
                        if (oe->type != OBJ_COMMIT)
                                die("Mark :%" PRIuMAX " not a commit", idnum);
                        oidcpy(&n->oid, &oe->idx.oid);
-               } else if (!get_oid(from, &n->oid)) {
+               } else if (!repo_get_oid(the_repository, from, &n->oid)) {
                        unsigned long size;
                        char *buf = read_object_with_reference(the_repository,
                                                               &n->oid,
@@ -2827,7 +2834,7 @@ static void parse_new_tag(const char *arg)
                oe = find_mark(marks, from_mark);
                type = oe->type;
                oidcpy(&oid, &oe->idx.oid);
-       } else if (!get_oid(from, &oid)) {
+       } else if (!repo_get_oid(the_repository, from, &oid)) {
                struct object_entry *oe = find_object(&oid);
                if (!oe) {
                        type = oid_object_info(the_repository, &oid, NULL);
@@ -2936,7 +2943,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
        char *buf;
 
        if (!oe || oe->pack_id == MAX_PACK_ID) {
-               buf = read_object_file(oid, &type, &size);
+               buf = repo_read_object_file(the_repository, oid, &type, &size);
        } else {
                type = oe->type;
                buf = gfi_unpack_entry(oe, &size);
@@ -3044,7 +3051,8 @@ static struct object_entry *dereference(struct object_entry *oe,
                buf = gfi_unpack_entry(oe, &size);
        } else {
                enum object_type unused;
-               buf = read_object_file(oid, &unused, &size);
+               buf = repo_read_object_file(the_repository, oid, &unused,
+                                           &size);
        }
        if (!buf)
                die("Can't load object %s", oid_to_hex(oid));
@@ -3245,7 +3253,7 @@ static void parse_alias(void)
 static char* make_fast_import_path(const char *path)
 {
        if (!relative_marks_paths || is_absolute_path(path))
-               return xstrdup(path);
+               return prefix_filename(global_prefix, path);
        return git_pathdup("info/fast-import/%s", path);
 }
 
@@ -3316,9 +3324,11 @@ static void option_cat_blob_fd(const char *fd)
 
 static void option_export_pack_edges(const char *edges)
 {
+       char *fn = prefix_filename(global_prefix, edges);
        if (pack_edges)
                fclose(pack_edges);
-       pack_edges = xfopen(edges, "a");
+       pack_edges = xfopen(fn, "a");
+       free(fn);
 }
 
 static void option_rewrite_submodules(const char *arg, struct string_list *list)
@@ -3333,11 +3343,13 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
        f++;
        CALLOC_ARRAY(ms, 1);
 
+       f = prefix_filename(global_prefix, f);
        fp = fopen(f, "r");
        if (!fp)
                die_errno("cannot read '%s'", f);
        read_mark_file(&ms, fp, insert_oid_entry);
        fclose(fp);
+       free(f);
 
        string_list_insert(list, s)->util = ms;
 }
@@ -3551,6 +3563,7 @@ int cmd_fast_import(int argc, const char **argv, const char *prefix)
 
        global_argc = argc;
        global_argv = argv;
+       global_prefix = prefix;
 
        rc_free = mem_pool_alloc(&fi_mem_pool, cmd_save * sizeof(*rc_free));
        for (i = 0; i < (cmd_save - 1); i++)
index afe679368deec2a0288de1606259b73847ce434b..44c05ee86cc7048e72e455f4c2a28a1d42a1f7fa 100644 (file)
@@ -1,4 +1,7 @@
 #include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
 #include "pkt-line.h"
 #include "fetch-pack.h"
 #include "remote.h"
@@ -40,7 +43,7 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
        (*sought)[*nr - 1] = ref;
 }
 
-int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
 {
        int i, ret;
        struct ref *ref = NULL;
@@ -211,8 +214,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
                int flags = args.verbose ? CONNECT_VERBOSE : 0;
                if (args.diag_url)
                        flags |= CONNECT_DIAG_URL;
-               conn = git_connect(fd, dest, args.uploadpack,
-                                  flags);
+               conn = git_connect(fd, dest, "git-upload-pack",
+                                  args.uploadpack, flags);
                if (!conn)
                        return args.diag_url ? 0 : 1;
        }
index a09606b472622c133a683513ffdbe184952f2b01..eed4a7cdb6c1d672ab7324ea129d83ea312b688e 100644 (file)
@@ -1,15 +1,20 @@
 /*
  * "git fetch"
  */
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
 #include "config.h"
+#include "gettext.h"
+#include "environment.h"
+#include "hex.h"
 #include "repository.h"
 #include "refs.h"
 #include "refspec.h"
-#include "object-store.h"
+#include "object-name.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"
 #include "strvec.h"
 #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"
 #include "branch.h"
 #include "promisor-remote.h"
 #include "commit-graph.h"
 #include "shallow.h"
+#include "trace.h"
+#include "trace2.h"
 #include "worktree.h"
 #include "bundle-uri.h"
 
@@ -47,25 +57,35 @@ enum {
        TAGS_SET = 2
 };
 
-static int fetch_prune_config = -1; /* unspecified */
-static int fetch_show_forced_updates = 1;
+enum display_format {
+       DISPLAY_FORMAT_FULL,
+       DISPLAY_FORMAT_COMPACT,
+       DISPLAY_FORMAT_PORCELAIN,
+};
+
+struct display_state {
+       struct strbuf buf;
+
+       int refcol_width;
+       enum display_format format;
+
+       char *url;
+       int url_len, shown_url;
+};
+
 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? */
 
-static int all, append, dry_run, force, keep, multiple, update_head_ok;
+static int append, dry_run, force, keep, update_head_ok;
 static int write_fetch_head = 1;
 static int verbosity, deepen_relative, set_upstream, refetch;
 static int progress = -1;
-static int enable_auto_gc = 1;
-static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
-static int max_jobs = -1, submodule_fetch_jobs_config = -1;
-static int fetch_parallel_config = 1;
+static int tags = TAGS_DEFAULT, update_shallow, deepen;
 static int atomic_fetch;
 static enum transport_family family;
 static const char *depth;
@@ -75,60 +95,77 @@ 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 const char *submodule_prefix = "";
-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
-static int shown_url = 0;
 static struct refspec refmap = REFSPEC_INIT_FETCH;
 static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
 static struct string_list server_options = STRING_LIST_INIT_DUP;
 static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
-static int fetch_write_commit_graph = -1;
-static int stdin_refspecs = 0;
-static int negotiate_only;
 
-static int git_fetch_config(const char *k, const char *v, void *cb)
+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,
+                           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;
        }
 
-       return git_default_config(k, v, cb);
+       if (!strcmp(k, "fetch.output")) {
+               if (!v)
+                       return config_error_nonbool(k);
+               else if (!strcasecmp(v, "full"))
+                       fetch_config->display_format = DISPLAY_FORMAT_FULL;
+               else if (!strcasecmp(v, "compact"))
+                       fetch_config->display_format = DISPLAY_FORMAT_COMPACT;
+               else
+                       die(_("invalid value for '%s': '%s'"),
+                           "fetch.output", v);
+       }
+
+       return git_default_config(k, v, ctx, cb);
 }
 
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
@@ -144,92 +181,6 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
        return 0;
 }
 
-static struct option builtin_fetch_options[] = {
-       OPT__VERBOSITY(&verbosity),
-       OPT_BOOL(0, "all", &all,
-                N_("fetch from all remotes")),
-       OPT_BOOL(0, "set-upstream", &set_upstream,
-                N_("set upstream for git pull/fetch")),
-       OPT_BOOL('a', "append", &append,
-                N_("append to .git/FETCH_HEAD instead of overwriting")),
-       OPT_BOOL(0, "atomic", &atomic_fetch,
-                N_("use atomic transaction to update references")),
-       OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
-                  N_("path to upload pack on remote end")),
-       OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
-       OPT_BOOL('m', "multiple", &multiple,
-                N_("fetch from multiple remotes")),
-       OPT_SET_INT('t', "tags", &tags,
-                   N_("fetch all tags and associated objects"), TAGS_SET),
-       OPT_SET_INT('n', NULL, &tags,
-                   N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
-       OPT_INTEGER('j', "jobs", &max_jobs,
-                   N_("number of submodules fetched in parallel")),
-       OPT_BOOL(0, "prefetch", &prefetch,
-                N_("modify the refspec to place all refs within refs/prefetch/")),
-       OPT_BOOL('p', "prune", &prune,
-                N_("prune remote-tracking branches no longer on remote")),
-       OPT_BOOL('P', "prune-tags", &prune_tags,
-                N_("prune local tags no longer on remote and clobber changed tags")),
-       OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
-                   N_("control recursive fetching of submodules"),
-                   PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
-       OPT_BOOL(0, "dry-run", &dry_run,
-                N_("dry run")),
-       OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
-                N_("write fetched references to the FETCH_HEAD file")),
-       OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
-       OPT_BOOL('u', "update-head-ok", &update_head_ok,
-                   N_("allow updating of HEAD ref")),
-       OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
-       OPT_STRING(0, "depth", &depth, N_("depth"),
-                  N_("deepen history of shallow clone")),
-       OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
-                  N_("deepen history of shallow repository based on time")),
-       OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
-                       N_("deepen history of shallow clone, excluding rev")),
-       OPT_INTEGER(0, "deepen", &deepen_relative,
-                   N_("deepen history of shallow clone")),
-       OPT_SET_INT_F(0, "unshallow", &unshallow,
-                     N_("convert to a complete repository"),
-                     1, PARSE_OPT_NONEG),
-       OPT_SET_INT_F(0, "refetch", &refetch,
-                     N_("re-fetch without negotiating common commits"),
-                     1, PARSE_OPT_NONEG),
-       { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
-                  N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
-       OPT_CALLBACK_F(0, "recurse-submodules-default",
-                  &recurse_submodules_default, N_("on-demand"),
-                  N_("default for recursive fetching of submodules "
-                     "(lower priority than config files)"),
-                  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"),
-                      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_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,
-                N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
-       OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
-       OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
-                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,
-                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")),
-       OPT_BOOL(0, "stdin", &stdin_refspecs,
-                N_("accept refspecs from stdin")),
-       OPT_END()
-};
-
 static void unlock_pack(unsigned int flags)
 {
        if (gtransport)
@@ -407,9 +358,9 @@ static void find_non_local_tags(const struct ref *refs,
                 */
                if (ends_with(ref->name, "^{}")) {
                        if (item &&
-                           !has_object_file_with_flags(&ref->old_oid, quick_flags) &&
+                           !repo_has_object_file_with_flags(the_repository, &ref->old_oid, quick_flags) &&
                            !oidset_contains(&fetch_oids, &ref->old_oid) &&
-                           !has_object_file_with_flags(&item->oid, quick_flags) &&
+                           !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
                            !oidset_contains(&fetch_oids, &item->oid))
                                clear_item(item);
                        item = NULL;
@@ -423,7 +374,7 @@ static void find_non_local_tags(const struct ref *refs,
                 * fetch.
                 */
                if (item &&
-                   !has_object_file_with_flags(&item->oid, quick_flags) &&
+                   !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
                    !oidset_contains(&fetch_oids, &item->oid))
                        clear_item(item);
 
@@ -444,7 +395,7 @@ static void find_non_local_tags(const struct ref *refs,
         * checked to see if it needs fetching.
         */
        if (item &&
-           !has_object_file_with_flags(&item->oid, quick_flags) &&
+           !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
            !oidset_contains(&fetch_oids, &item->oid))
                clear_item(item);
 
@@ -741,76 +692,97 @@ out:
        return ret;
 }
 
-static int refcol_width = 10;
-static int compact_format;
-
-static void adjust_refcol_width(const struct ref *ref)
+static int refcol_width(const struct ref *ref_map, int compact_format)
 {
-       int max, rlen, llen, len;
+       const struct ref *ref;
+       int max, width = 10;
 
-       /* uptodate lines are only shown on high verbosity level */
-       if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
-               return;
+       max = term_columns();
+       if (compact_format)
+               max = max * 2 / 3;
 
-       max    = term_columns();
-       rlen   = utf8_strwidth(prettify_refname(ref->name));
+       for (ref = ref_map; ref; ref = ref->next) {
+               int rlen, llen = 0, len;
 
-       llen   = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+               if (ref->status == REF_STATUS_REJECT_SHALLOW ||
+                   !ref->peer_ref ||
+                   !strcmp(ref->name, "HEAD"))
+                       continue;
 
-       /*
-        * rough estimation to see if the output line is too long and
-        * should not be counted (we can't do precise calculation
-        * anyway because we don't know if the error explanation part
-        * will be printed in update_local_ref)
-        */
-       if (compact_format) {
-               llen = 0;
-               max = max * 2 / 3;
+               /* uptodate lines are only shown on high verbosity level */
+               if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
+                       continue;
+
+               rlen = utf8_strwidth(prettify_refname(ref->name));
+               if (!compact_format)
+                       llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+               /*
+                * rough estimation to see if the output line is too long and
+                * should not be counted (we can't do precise calculation
+                * anyway because we don't know if the error explanation part
+                * will be printed in update_local_ref)
+                */
+               len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+               if (len >= max)
+                       continue;
+
+               if (width < rlen)
+                       width = rlen;
        }
-       len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
-       if (len >= max)
-               return;
 
-       /*
-        * Not precise calculation for compact mode because '*' can
-        * appear on the left hand side of '->' and shrink the column
-        * back.
-        */
-       if (refcol_width < rlen)
-               refcol_width = rlen;
+       return width;
 }
 
-static void prepare_format_display(struct ref *ref_map)
+static void display_state_init(struct display_state *display_state, struct ref *ref_map,
+                              const char *raw_url, enum display_format format)
 {
-       struct ref *rm;
-       const char *format = "full";
+       int i;
 
-       if (verbosity < 0)
-               return;
+       memset(display_state, 0, sizeof(*display_state));
+       strbuf_init(&display_state->buf, 0);
+       display_state->format = format;
 
-       git_config_get_string_tmp("fetch.output", &format);
-       if (!strcasecmp(format, "full"))
-               compact_format = 0;
-       else if (!strcasecmp(format, "compact"))
-               compact_format = 1;
+       if (raw_url)
+               display_state->url = transport_anonymize_url(raw_url);
        else
-               die(_("invalid value for '%s': '%s'"),
-                   "fetch.output", format);
+               display_state->url = xstrdup("foreign");
 
-       for (rm = ref_map; rm; rm = rm->next) {
-               if (rm->status == REF_STATUS_REJECT_SHALLOW ||
-                   !rm->peer_ref ||
-                   !strcmp(rm->name, "HEAD"))
-                       continue;
+       display_state->url_len = strlen(display_state->url);
+       for (i = display_state->url_len - 1; display_state->url[i] == '/' && 0 <= i; i--)
+               ;
+       display_state->url_len = i + 1;
+       if (4 < i && !strncmp(".git", display_state->url + i - 3, 4))
+               display_state->url_len = i - 3;
 
-               adjust_refcol_width(rm);
+       if (verbosity < 0)
+               return;
+
+       switch (display_state->format) {
+       case DISPLAY_FORMAT_FULL:
+       case DISPLAY_FORMAT_COMPACT:
+               display_state->refcol_width = refcol_width(ref_map,
+                                                          display_state->format == DISPLAY_FORMAT_COMPACT);
+               break;
+       case DISPLAY_FORMAT_PORCELAIN:
+               /* We don't need to precompute anything here. */
+               break;
+       default:
+               BUG("unexpected display format %d", display_state->format);
        }
 }
 
-static void print_remote_to_local(struct strbuf *display,
+static void display_state_release(struct display_state *display_state)
+{
+       strbuf_release(&display_state->buf);
+       free(display_state->url);
+}
+
+static void print_remote_to_local(struct display_state *display_state,
                                  const char *remote, const char *local)
 {
-       strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
+       strbuf_addf(&display_state->buf, "%-*s -> %s",
+                   display_state->refcol_width, remote, local);
 }
 
 static int find_and_replace(struct strbuf *haystack,
@@ -840,14 +812,14 @@ static int find_and_replace(struct strbuf *haystack,
        return 1;
 }
 
-static void print_compact(struct strbuf *display,
+static void print_compact(struct display_state *display_state,
                          const char *remote, const char *local)
 {
        struct strbuf r = STRBUF_INIT;
        struct strbuf l = STRBUF_INIT;
 
        if (!strcmp(remote, local)) {
-               strbuf_addf(display, "%-*s -> *", refcol_width, remote);
+               strbuf_addf(&display_state->buf, "%-*s -> *", display_state->refcol_width, remote);
                return;
        }
 
@@ -856,40 +828,74 @@ static void print_compact(struct strbuf *display,
 
        if (!find_and_replace(&r, local, "*"))
                find_and_replace(&l, remote, "*");
-       print_remote_to_local(display, r.buf, l.buf);
+       print_remote_to_local(display_state, r.buf, l.buf);
 
        strbuf_release(&r);
        strbuf_release(&l);
 }
 
-static void format_display(struct strbuf *display, char code,
-                          const char *summary, const char *error,
-                          const char *remote, const char *local,
-                          int summary_width)
+static void display_ref_update(struct display_state *display_state, char code,
+                              const char *summary, const char *error,
+                              const char *remote, const char *local,
+                              const struct object_id *old_oid,
+                              const struct object_id *new_oid,
+                              int summary_width)
 {
-       int width;
+       FILE *f = stderr;
 
        if (verbosity < 0)
                return;
 
-       width = (summary_width + strlen(summary) - gettext_width(summary));
+       strbuf_reset(&display_state->buf);
 
-       strbuf_addf(display, "%c %-*s ", code, width, summary);
-       if (!compact_format)
-               print_remote_to_local(display, remote, local);
-       else
-               print_compact(display, remote, local);
-       if (error)
-               strbuf_addf(display, "  (%s)", error);
+       switch (display_state->format) {
+       case DISPLAY_FORMAT_FULL:
+       case DISPLAY_FORMAT_COMPACT: {
+               int width;
+
+               if (!display_state->shown_url) {
+                       strbuf_addf(&display_state->buf, _("From %.*s\n"),
+                                   display_state->url_len, display_state->url);
+                       display_state->shown_url = 1;
+               }
+
+               width = (summary_width + strlen(summary) - gettext_width(summary));
+               remote = prettify_refname(remote);
+               local = prettify_refname(local);
+
+               strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
+
+               if (display_state->format != DISPLAY_FORMAT_COMPACT)
+                       print_remote_to_local(display_state, remote, local);
+               else
+                       print_compact(display_state, remote, local);
+
+               if (error)
+                       strbuf_addf(&display_state->buf, "  (%s)", error);
+
+               break;
+       }
+       case DISPLAY_FORMAT_PORCELAIN:
+               strbuf_addf(&display_state->buf, "%c %s %s %s", code,
+                           oid_to_hex(old_oid), oid_to_hex(new_oid), local);
+               f = stdout;
+               break;
+       default:
+               BUG("unexpected display format %d", display_state->format);
+       };
+       strbuf_addch(&display_state->buf, '\n');
+
+       fputs(display_state->buf.buf, f);
 }
 
 static int update_local_ref(struct ref *ref,
                            struct ref_transaction *transaction,
-                           const char *remote, const struct ref *remote_ref,
-                           struct strbuf *display, int summary_width)
+                           struct display_state *display_state,
+                           const struct ref *remote_ref,
+                           int summary_width,
+                           const struct fetch_config *config)
 {
        struct commit *current = NULL, *updated;
-       const char *pretty_ref = prettify_refname(ref->name);
        int fast_forward = 0;
 
        if (!repo_has_object_file(the_repository, &ref->new_oid))
@@ -897,8 +903,9 @@ static int update_local_ref(struct ref *ref,
 
        if (oideq(&ref->old_oid, &ref->new_oid)) {
                if (verbosity > 0)
-                       format_display(display, '=', _("[up to date]"), NULL,
-                                      remote, pretty_ref, summary_width);
+                       display_ref_update(display_state, '=', _("[up to date]"), NULL,
+                                          remote_ref->name, ref->name,
+                                          &ref->old_oid, &ref->new_oid, summary_width);
                return 0;
        }
 
@@ -909,9 +916,10 @@ static int update_local_ref(struct ref *ref,
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
-               format_display(display, '!', _("[rejected]"),
-                              _("can't fetch into checked-out branch"),
-                              remote, pretty_ref, summary_width);
+               display_ref_update(display_state, '!', _("[rejected]"),
+                                  _("can't fetch into checked-out branch"),
+                                  remote_ref->name, ref->name,
+                                  &ref->old_oid, &ref->new_oid, summary_width);
                return 1;
        }
 
@@ -920,13 +928,16 @@ static int update_local_ref(struct ref *ref,
                if (force || ref->force) {
                        int r;
                        r = s_update_ref("updating tag", ref, transaction, 0);
-                       format_display(display, r ? '!' : 't', _("[tag update]"),
-                                      r ? _("unable to update local ref") : NULL,
-                                      remote, pretty_ref, summary_width);
+                       display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
+                                          r ? _("unable to update local ref") : NULL,
+                                          remote_ref->name, ref->name,
+                                          &ref->old_oid, &ref->new_oid, summary_width);
                        return r;
                } else {
-                       format_display(display, '!', _("[rejected]"), _("would clobber existing tag"),
-                                      remote, pretty_ref, summary_width);
+                       display_ref_update(display_state, '!', _("[rejected]"),
+                                          _("would clobber existing tag"),
+                                          remote_ref->name, ref->name,
+                                          &ref->old_oid, &ref->new_oid, summary_width);
                        return 1;
                }
        }
@@ -944,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 {
@@ -957,15 +967,17 @@ static int update_local_ref(struct ref *ref,
                }
 
                r = s_update_ref(msg, ref, transaction, 0);
-               format_display(display, r ? '!' : '*', what,
-                              r ? _("unable to update local ref") : NULL,
-                              remote, pretty_ref, summary_width);
+               display_ref_update(display_state, r ? '!' : '*', what,
+                                  r ? _("unable to update local ref") : NULL,
+                                  remote_ref->name, ref->name,
+                                  &ref->old_oid, &ref->new_oid, summary_width);
                return r;
        }
 
-       if (fetch_show_forced_updates) {
+       if (config->show_forced_updates) {
                uint64_t t_before = getnanotime();
-               fast_forward = in_merge_bases(current, updated);
+               fast_forward = repo_in_merge_bases(the_repository, current,
+                                                  updated);
                forced_updates_ms += (getnanotime() - t_before) / 1000000;
        } else {
                fast_forward = 1;
@@ -979,9 +991,10 @@ static int update_local_ref(struct ref *ref,
                strbuf_addstr(&quickref, "..");
                strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
                r = s_update_ref("fast-forward", ref, transaction, 1);
-               format_display(display, r ? '!' : ' ', quickref.buf,
-                              r ? _("unable to update local ref") : NULL,
-                              remote, pretty_ref, summary_width);
+               display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
+                                  r ? _("unable to update local ref") : NULL,
+                                  remote_ref->name, ref->name,
+                                  &ref->old_oid, &ref->new_oid, summary_width);
                strbuf_release(&quickref);
                return r;
        } else if (force || ref->force) {
@@ -991,14 +1004,16 @@ static int update_local_ref(struct ref *ref,
                strbuf_addstr(&quickref, "...");
                strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
                r = s_update_ref("forced-update", ref, transaction, 1);
-               format_display(display, r ? '!' : '+', quickref.buf,
-                              r ? _("unable to update local ref") : _("forced update"),
-                              remote, pretty_ref, summary_width);
+               display_ref_update(display_state, r ? '!' : '+', quickref.buf,
+                                  r ? _("unable to update local ref") : _("forced update"),
+                                  remote_ref->name, ref->name,
+                                  &ref->old_oid, &ref->new_oid, summary_width);
                strbuf_release(&quickref);
                return r;
        } else {
-               format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
-                              remote, pretty_ref, summary_width);
+               display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"),
+                                  remote_ref->name, ref->name,
+                                  &ref->old_oid, &ref->new_oid, summary_width);
                return 1;
        }
 }
@@ -1108,39 +1123,35 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
    "'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
    "to avoid this check\n");
 
-static int store_updated_refs(const char *raw_url, const char *remote_name,
+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 url_len, i, rc = 0;
+       int rc = 0;
        struct strbuf note = STRBUF_INIT;
        const char *what, *kind;
        struct ref *rm;
-       char *url;
        int want_status;
        int summary_width = 0;
 
        if (verbosity >= 0)
                summary_width = transport_summary_width(ref_map);
 
-       if (raw_url)
-               url = transport_anonymize_url(raw_url);
-       else
-               url = xstrdup("foreign");
-
        if (!connectivity_checked) {
                struct check_connected_options opt = CHECK_CONNECTED_INIT;
 
+               opt.exclude_hidden_refs_section = "fetch";
                rm = ref_map;
                if (check_connected(iterate_ref_map, &rm, &opt)) {
-                       rc = error(_("%s did not send all necessary objects\n"), url);
+                       rc = error(_("%s did not send all necessary objects\n"),
+                                  display_state->url);
                        goto abort;
                }
        }
 
-       prepare_format_display(ref_map);
-
        /*
         * We do a pass for each fetch_head_status type in their enum order, so
         * merged entries are written before not-for-merge. That lets readers
@@ -1200,7 +1211,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                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);
                        }
@@ -1208,25 +1219,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                        if (!strcmp(rm->name, "HEAD")) {
                                kind = "";
                                what = "";
-                       }
-                       else if (skip_prefix(rm->name, "refs/heads/", &what))
+                       } else if (skip_prefix(rm->name, "refs/heads/", &what)) {
                                kind = "branch";
-                       else if (skip_prefix(rm->name, "refs/tags/", &what))
+                       } else if (skip_prefix(rm->name, "refs/tags/", &what)) {
                                kind = "tag";
-                       else if (skip_prefix(rm->name, "refs/remotes/", &what))
+                       } else if (skip_prefix(rm->name, "refs/remotes/", &what)) {
                                kind = "remote-tracking branch";
-                       else {
+                       else {
                                kind = "";
                                what = rm->name;
                        }
 
-                       url_len = strlen(url);
-                       for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
-                               ;
-                       url_len = i + 1;
-                       if (4 < i && !strncmp(".git", url + i - 3, 4))
-                               url_len = i - 3;
-
                        strbuf_reset(&note);
                        if (*what) {
                                if (*kind)
@@ -1236,12 +1239,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 
                        append_fetch_head(fetch_head, &rm->old_oid,
                                          rm->fetch_head_status,
-                                         note.buf, url, url_len);
+                                         note.buf, display_state->url,
+                                         display_state->url_len);
 
-                       strbuf_reset(&note);
                        if (ref) {
-                               rc |= update_local_ref(ref, transaction, what,
-                                                      rm, &note, summary_width);
+                               rc |= update_local_ref(ref, transaction, display_state,
+                                                      rm, summary_width, config);
                                free(ref);
                        } else if (write_fetch_head || dry_run) {
                                /*
@@ -1249,18 +1252,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                 * would be written to FETCH_HEAD, if --dry-run
                                 * is set).
                                 */
-                               format_display(&note, '*',
-                                              *kind ? kind : "branch", NULL,
-                                              *what ? what : "HEAD",
-                                              "FETCH_HEAD", summary_width);
-                       }
-                       if (note.len) {
-                               if (!shown_url) {
-                                       fprintf(stderr, _("From %.*s\n"),
-                                                       url_len, url);
-                                       shown_url = 1;
-                               }
-                               fprintf(stderr, " %s\n", note.buf);
+                               display_ref_update(display_state, '*',
+                                                  *kind ? kind : "branch", NULL,
+                                                  rm->name,
+                                                  "FETCH_HEAD",
+                                                  &rm->new_oid, &rm->old_oid,
+                                                  summary_width);
                        }
                }
        }
@@ -1271,7 +1268,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                      "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),
@@ -1281,7 +1278,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 
  abort:
        strbuf_release(&note);
-       free(url);
        return rc;
 }
 
@@ -1319,19 +1315,22 @@ static int check_exist_and_connected(struct ref *ref_map)
         * we need all direct targets to exist.
         */
        for (r = rm; r; r = r->next) {
-               if (!has_object_file_with_flags(&r->old_oid,
-                                               OBJECT_INFO_SKIP_FETCH_OBJECT))
+               if (!repo_has_object_file_with_flags(the_repository, &r->old_oid,
+                                                    OBJECT_INFO_SKIP_FETCH_OBJECT))
                        return -1;
        }
 
        opt.quiet = 1;
+       opt.exclude_hidden_refs_section = "fetch";
        return check_connected(iterate_ref_map, &rm, &opt);
 }
 
-static int fetch_and_consume_refs(struct transport *transport,
+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;
@@ -1352,9 +1351,9 @@ static int fetch_and_consume_refs(struct transport *transport,
        }
 
        trace2_region_enter("fetch", "consume_refs", the_repository);
-       ret = store_updated_refs(transport->url, transport->remote->name,
+       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:
@@ -1362,32 +1361,18 @@ out:
        return ret;
 }
 
-static int prune_refs(struct refspec *rs,
+static int prune_refs(struct display_state *display_state,
+                     struct refspec *rs,
                      struct ref_transaction *transaction,
-                     struct ref *ref_map,
-                     const char *raw_url)
+                     struct ref *ref_map)
 {
-       int url_len, i, result = 0;
+       int result = 0;
        struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
        struct strbuf err = STRBUF_INIT;
-       char *url;
        const char *dangling_msg = dry_run
                ? _("   (%s will become dangling)")
                : _("   (%s has become dangling)");
 
-       if (raw_url)
-               url = transport_anonymize_url(raw_url);
-       else
-               url = xstrdup("foreign");
-
-       url_len = strlen(url);
-       for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
-               ;
-
-       url_len = i + 1;
-       if (4 < i && !strncmp(".git", url + i - 3, 4))
-               url_len = i - 3;
-
        if (!dry_run) {
                if (transaction) {
                        for (ref = stale_refs; ref; ref = ref->next) {
@@ -1411,23 +1396,16 @@ static int prune_refs(struct refspec *rs,
                int summary_width = transport_summary_width(stale_refs);
 
                for (ref = stale_refs; ref; ref = ref->next) {
-                       struct strbuf sb = STRBUF_INIT;
-                       if (!shown_url) {
-                               fprintf(stderr, _("From %.*s\n"), url_len, url);
-                               shown_url = 1;
-                       }
-                       format_display(&sb, '-', _("[deleted]"), NULL,
-                                      _("(none)"), prettify_refname(ref->name),
-                                      summary_width);
-                       fprintf(stderr, " %s\n",sb.buf);
-                       strbuf_release(&sb);
+                       display_ref_update(display_state, '-', _("[deleted]"), NULL,
+                                          _("(none)"), ref->name,
+                                          &ref->new_oid, &ref->old_oid,
+                                          summary_width);
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
        }
 
 cleanup:
        strbuf_release(&err);
-       free(url);
        free_refs(stale_refs);
        return result;
 }
@@ -1487,7 +1465,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
                int old_nr;
                if (!has_glob_specials(s)) {
                        struct object_id oid;
-                       if (get_oid(s, &oid))
+                       if (repo_get_oid(the_repository, s, &oid))
                                die(_("%s is not a valid object"), s);
                        if (!has_object(the_repository, &oid, 0))
                                die(_("the object %s does not exist"), s);
@@ -1542,10 +1520,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
        return transport;
 }
 
-static int backfill_tags(struct transport *transport,
+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;
 
@@ -1566,7 +1546,8 @@ static int backfill_tags(struct transport *transport,
        transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
        transport_set_option(transport, TRANS_OPT_DEPTH, "0");
        transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
-       retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head);
+       retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map,
+                                        fetch_head, config);
 
        if (gsecondary) {
                transport_disconnect(gsecondary);
@@ -1577,10 +1558,12 @@ static int backfill_tags(struct transport *transport,
 }
 
 static int do_fetch(struct transport *transport,
-                   struct refspec *rs)
+                   struct refspec *rs,
+                   const struct fetch_config *config)
 {
        struct ref_transaction *transaction = NULL;
        struct ref *ref_map = NULL;
+       struct display_state display_state = { 0 };
        int autotags = (transport->remote->fetch_tags == 1);
        int retcode = 0;
        const struct ref *remote_refs;
@@ -1662,6 +1645,9 @@ static int do_fetch(struct transport *transport,
        if (retcode)
                goto cleanup;
 
+       display_state_init(&display_state, ref_map, transport->url,
+                          config->display_format);
+
        if (atomic_fetch) {
                transaction = ref_transaction_begin(&err);
                if (!transaction) {
@@ -1679,17 +1665,17 @@ static int do_fetch(struct transport *transport,
                 * don't care whether --tags was specified.
                 */
                if (rs->nr) {
-                       retcode = prune_refs(rs, transaction, ref_map, transport->url);
+                       retcode = prune_refs(&display_state, rs, transaction, ref_map);
                } else {
-                       retcode = prune_refs(&transport->remote->fetch,
-                                            transaction, ref_map,
-                                            transport->url);
+                       retcode = prune_refs(&display_state, &transport->remote->fetch,
+                                            transaction, ref_map);
                }
                if (retcode != 0)
                        retcode = 1;
        }
 
-       if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head)) {
+       if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
+                                  &fetch_head, config)) {
                retcode = 1;
                goto cleanup;
        }
@@ -1711,8 +1697,8 @@ static int do_fetch(struct transport *transport,
                         * when `--atomic` is passed: in that case we'll abort
                         * the transaction and don't commit anything.
                         */
-                       if (backfill_tags(transport, transaction, tags_ref_map,
-                                         &fetch_head))
+                       if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
+                                         &fetch_head, config))
                                retcode = 1;
                }
 
@@ -1794,6 +1780,7 @@ cleanup:
                error("%s", err.buf);
        }
 
+       display_state_release(&display_state);
        close_fetch_head(&fetch_head);
        strbuf_release(&err);
        free_refs(ref_map);
@@ -1813,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;
 
@@ -1848,7 +1837,8 @@ static int add_remote_or_group(const char *name, struct string_list *list)
        return 1;
 }
 
-static void add_options_to_argv(struct strvec *argv)
+static void add_options_to_argv(struct strvec *argv,
+                               const struct fetch_config *config)
 {
        if (dry_run)
                strvec_push(argv, "--dry-run");
@@ -1862,9 +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_ON_DEMAND)
+       else if (config->recurse_submodules == RECURSE_SUBMODULES_OFF)
+               strvec_push(argv, "--no-recurse-submodules");
+       else if (config->recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
                strvec_push(argv, "--recurse-submodules=on-demand");
        if (tags == TAGS_SET)
                strvec_push(argv, "--tags");
@@ -1880,6 +1872,10 @@ static void add_options_to_argv(struct strvec *argv)
                strvec_push(argv, "--ipv4");
        else if (family == TRANSPORT_FAMILY_IPV6)
                strvec_push(argv, "--ipv6");
+       if (!write_fetch_head)
+               strvec_push(argv, "--no-write-fetch-head");
+       if (config->display_format == DISPLAY_FORMAT_PORCELAIN)
+               strvec_pushf(argv, "--porcelain");
 }
 
 /* Fetch multiple remotes in parallel */
@@ -1888,9 +1884,11 @@ struct parallel_fetch_state {
        const char **argv;
        struct string_list *remotes;
        int next, result;
+       const struct fetch_config *config;
 };
 
-static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
+static int fetch_next_remote(struct child_process *cp,
+                            struct strbuf *out UNUSED,
                             void *cb, void **task_cb)
 {
        struct parallel_fetch_state *state = cb;
@@ -1906,13 +1904,14 @@ static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
        strvec_push(&cp->args, remote);
        cp->git_cmd = 1;
 
-       if (verbosity >= 0)
+       if (verbosity >= 0 && state->config->display_format != DISPLAY_FORMAT_PORCELAIN)
                printf(_("Fetching %s\n"), remote);
 
        return 1;
 }
 
-static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
+static int fetch_failed_to_start(struct strbuf *out UNUSED,
+                                void *cb, void *task_cb)
 {
        struct parallel_fetch_state *state = cb;
        const char *remote = task_cb;
@@ -1937,7 +1936,8 @@ static int fetch_finished(int result, struct strbuf *out,
        return 0;
 }
 
-static int fetch_multiple(struct string_list *list, int max_children)
+static int fetch_multiple(struct string_list *list, int max_children,
+                         const struct fetch_config *config)
 {
        int i, result = 0;
        struct strvec argv = STRVEC_INIT;
@@ -1948,12 +1948,17 @@ static int fetch_multiple(struct string_list *list, int max_children)
                        return errcode;
        }
 
-       strvec_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+       /*
+        * Cancel out the fetch.bundleURI config when running subprocesses,
+        * to avoid fetching from the same bundle list multiple times.
+        */
+       strvec_pushl(&argv, "-c", "fetch.bundleURI=",
+                    "fetch", "--append", "--no-auto-gc",
                     "--no-write-commit-graph", NULL);
-       add_options_to_argv(&argv);
+       add_options_to_argv(&argv, config);
 
        if (max_children != 1 && list->nr != 1) {
-               struct parallel_fetch_state state = { argv.v, list, 0, 0 };
+               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",
@@ -1977,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)
+                       if (verbosity >= 0 && config->display_format != DISPLAY_FORMAT_PORCELAIN)
                                printf(_("Fetching %s\n"), name);
                        cmd.git_cmd = 1;
                        if (run_command(&cmd)) {
@@ -2007,7 +2012,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
         * If no prior partial clone/fetch and the current fetch DID NOT
         * request a partial-fetch, do a normal fetch.
         */
-       if (!has_promisor_remote() && !filter_options.choice)
+       if (!repo_has_promisor_remote(the_repository) && !filter_options.choice)
                return;
 
        /*
@@ -2032,7 +2037,8 @@ 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)
+                    int prune_tags_ok, int use_stdin_refspecs,
+                    const struct fetch_config *config)
 {
        struct refspec rs = REFSPEC_INIT_FETCH;
        int i;
@@ -2050,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;
        }
@@ -2060,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;
        }
@@ -2099,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);
+       exit_code = do_fetch(gtransport, &rs, config);
        sigchain_pop(SIGPIPE);
        refspec_clear(&rs);
        transport_disconnect(gtransport);
@@ -2109,12 +2115,116 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
 
 int cmd_fetch(int argc, const char **argv, const char *prefix)
 {
-       int i;
+       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;
        struct string_list list = STRING_LIST_INIT_DUP;
        struct remote *remote = NULL;
+       int all = 0, multiple = 0;
        int result = 0;
        int prune_tags_ok = 1;
+       int enable_auto_gc = 1;
+       int unshallow = 0;
+       int max_jobs = -1;
+       int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
+       int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
+       int fetch_write_commit_graph = -1;
+       int stdin_refspecs = 0;
+       int negotiate_only = 0;
+       int porcelain = 0;
+       int i;
+
+       struct option builtin_fetch_options[] = {
+               OPT__VERBOSITY(&verbosity),
+               OPT_BOOL(0, "all", &all,
+                        N_("fetch from all remotes")),
+               OPT_BOOL(0, "set-upstream", &set_upstream,
+                        N_("set upstream for git pull/fetch")),
+               OPT_BOOL('a', "append", &append,
+                        N_("append to .git/FETCH_HEAD instead of overwriting")),
+               OPT_BOOL(0, "atomic", &atomic_fetch,
+                        N_("use atomic transaction to update references")),
+               OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+                          N_("path to upload pack on remote end")),
+               OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
+               OPT_BOOL('m', "multiple", &multiple,
+                        N_("fetch from multiple remotes")),
+               OPT_SET_INT('t', "tags", &tags,
+                           N_("fetch all tags and associated objects"), TAGS_SET),
+               OPT_SET_INT('n', NULL, &tags,
+                           N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
+               OPT_INTEGER('j', "jobs", &max_jobs,
+                           N_("number of submodules fetched in parallel")),
+               OPT_BOOL(0, "prefetch", &prefetch,
+                        N_("modify the refspec to place all refs within refs/prefetch/")),
+               OPT_BOOL('p', "prune", &prune,
+                        N_("prune remote-tracking branches no longer on remote")),
+               OPT_BOOL('P', "prune-tags", &prune_tags,
+                        N_("prune local tags no longer on remote and clobber changed tags")),
+               OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
+                           N_("control recursive fetching of submodules"),
+                           PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
+               OPT_BOOL(0, "dry-run", &dry_run,
+                        N_("dry run")),
+               OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+               OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+                        N_("write fetched references to the FETCH_HEAD file")),
+               OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+               OPT_BOOL('u', "update-head-ok", &update_head_ok,
+                           N_("allow updating of HEAD ref")),
+               OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+               OPT_STRING(0, "depth", &depth, N_("depth"),
+                          N_("deepen history of shallow clone")),
+               OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
+                          N_("deepen history of shallow repository based on time")),
+               OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
+                               N_("deepen history of shallow clone, excluding rev")),
+               OPT_INTEGER(0, "deepen", &deepen_relative,
+                           N_("deepen history of shallow clone")),
+               OPT_SET_INT_F(0, "unshallow", &unshallow,
+                             N_("convert to a complete repository"),
+                             1, PARSE_OPT_NONEG),
+               OPT_SET_INT_F(0, "refetch", &refetch,
+                             N_("re-fetch without negotiating common commits"),
+                             1, PARSE_OPT_NONEG),
+               { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+                          N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+               OPT_CALLBACK_F(0, "recurse-submodules-default",
+                          &recurse_submodules_default, N_("on-demand"),
+                          N_("default for recursive fetching of submodules "
+                             "(lower priority than config files)"),
+                          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"),
+                              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_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,
+                        N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
+               OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+               OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
+                        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", &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")),
+               OPT_BOOL(0, "stdin", &stdin_refspecs,
+                        N_("accept refspecs from stdin")),
+               OPT_END()
+       };
 
        packet_trace_identity("fetch");
 
@@ -2128,7 +2238,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                free(anon);
        }
 
-       git_config(git_fetch_config, NULL);
+       git_config(git_fetch_config, &config);
        if (the_repository->gitdir) {
                prepare_repo_settings(the_repository);
                the_repository->settings.command_requires_full_index = 0;
@@ -2138,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) {
@@ -2149,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:
@@ -2158,15 +2268,35 @@ 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);
        }
 
+
+       if (porcelain) {
+               switch (recurse_submodules_cli) {
+               case RECURSE_SUBMODULES_OFF:
+               case RECURSE_SUBMODULES_DEFAULT:
+                       /*
+                        * Reference updates in submodules would be ambiguous
+                        * in porcelain mode, so we reject this combination.
+                        */
+                       config.recurse_submodules = RECURSE_SUBMODULES_OFF;
+                       break;
+
+               default:
+                       die(_("options '%s' and '%s' cannot be used together"),
+                           "--porcelain", "--recurse-submodules");
+               }
+
+               config.display_format = DISPLAY_FORMAT_PORCELAIN;
+       }
+
        if (negotiate_only && !negotiation_tip.nr)
                die(_("--negotiate-only needs one or more --negotiation-tip=*"));
 
@@ -2263,9 +2393,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                        printf("%s\n", oid_to_hex(oid));
                oidset_clear(&acked_commits);
        } else if (remote) {
-               if (filter_options.choice || has_promisor_remote())
+               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);
+               result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
+                                  &config);
        } else {
                int max_children = max_jobs;
 
@@ -2282,13 +2413,12 @@ 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);
+               result = fetch_multiple(&list, max_children, &config);
        }
 
-
        /*
         * This is only needed after fetch_one(), which does not fetch
         * submodules by itself.
@@ -2298,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);
+               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 8d8fd393f8925c93155091db4f0959b7f03c31bb..0f9855b680eb7bf4e534af40847e32af835cfa13 100644 (file)
@@ -1,6 +1,7 @@
 #include "builtin.h"
 #include "config.h"
 #include "fmt-merge-msg.h"
+#include "gettext.h"
 #include "parse-options.h"
 
 static const char * const fmt_merge_msg_usage[] = {
index 6f62f40d1263f44f8977125d9d54eca76f101685..350bfa6e811b8c53d94ba33083a03bf9d93437dc 100644 (file)
@@ -1,10 +1,13 @@
 #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"
 
 static char const * const for_each_ref_usage[] = {
        N_("git for-each-ref [<options>] [<pattern>]"),
@@ -19,12 +22,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        int i;
        struct ref_sorting *sorting;
        struct string_list sorting_options = STRING_LIST_INIT_DUP;
-       int maxcount = 0, icase = 0;
+       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;
+       int from_stdin = 0;
+       struct strvec vec = STRVEC_INIT;
 
        struct option opts[] = {
                OPT_BIT('s', "shell", &format.quote_style,
@@ -35,11 +40,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                        N_("quote placeholders suitably for python"), QUOTE_PYTHON),
                OPT_BIT(0 , "tcl",  &format.quote_style,
                        N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
+               OPT_BOOL(0, "omit-empty",  &omit_empty,
+                       N_("do not output a newline after empty formatted refs")),
 
                OPT_GROUP(""),
                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"),
@@ -49,11 +57,11 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
                OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
                OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+               OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
                OPT_END(),
        };
 
        memset(&array, 0, sizeof(array));
-       memset(&filter, 0, sizeof(filter));
 
        format.format = "%(objectname) %(objecttype)\t%(refname)";
 
@@ -75,9 +83,27 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
        filter.ignore_case = icase;
 
-       filter.name_patterns = argv;
+       if (from_stdin) {
+               struct strbuf line = STRBUF_INIT;
+
+               if (argv[0])
+                       die(_("unknown arguments supplied with --stdin"));
+
+               while (strbuf_getline(&line, stdin) != EOF)
+                       strvec_push(&vec, line.buf);
+
+               strbuf_release(&line);
+
+               /* vec.v is NULL-terminated, just like 'argv'. */
+               filter.name_patterns = vec.v;
+       } else {
+               filter.name_patterns = argv;
+       }
+
        filter.match_as_path = 1;
        filter_refs(&array, &filter, FILTER_REFS_ALL);
+       filter_ahead_behind(the_repository, &format, &array);
+
        ref_array_sort(sorting, &array);
 
        if (!maxcount || array.nr < maxcount)
@@ -88,14 +114,15 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                if (format_ref_array_item(array.items[i], &format, &output, &err))
                        die("%s", err.buf);
                fwrite(output.buf, 1, output.len, stdout);
-               putchar('\n');
+               if (output.len || !omit_empty)
+                       putchar('\n');
        }
 
        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 6aeac37148830d316f533e5399c79ed551fda2fe..28186b30f54818cdbb42a4876358b7ceb20d20e2 100644 (file)
@@ -1,7 +1,9 @@
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "path.h"
+#include "repository.h"
 #include "run-command.h"
 #include "string-list.h"
 
@@ -32,6 +34,7 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
        static const char *config_key = NULL;
        int i, result = 0;
        const struct string_list *values;
+       int err;
 
        const struct option options[] = {
                OPT_STRING(0, "config", &config_key, N_("config"),
@@ -45,14 +48,11 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
        if (!config_key)
                die(_("missing --config=<config>"));
 
-       values = repo_config_get_value_multi(the_repository,
-                                            config_key);
-
-       /*
-        * Do nothing on an empty list, which is equivalent to the case
-        * where the config variable does not exist at all.
-        */
-       if (!values)
+       err = repo_config_get_string_multi(the_repository, config_key, &values);
+       if (err < 0)
+               usage_msg_optf(_("got bad config --config=%s"),
+                              for_each_repo_usage, options, config_key);
+       else if (err)
                return 0;
 
        for (i = 0; !result && i < values->nr; i++)
index d207bd909b4b6da0671628c20bb29e98f427b550..611925905e4fd1d972565806156059016d2eb1a6 100644 (file)
@@ -1,6 +1,6 @@
-#define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "config.h"
 #include "commit.h"
 #include "streaming.h"
 #include "decorate.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.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"
 
 #define REACHABLE 0x0001
 #define SEEN      0x0002
@@ -51,6 +59,8 @@ static int name_objects;
 #define ERROR_REFS 010
 #define ERROR_COMMIT_GRAPH 020
 #define ERROR_MULTI_PACK_INDEX 040
+#define ERROR_PACK_REV_INDEX 0100
+#define ERROR_BITMAP 0200
 
 static const char *describe_object(const struct object_id *oid)
 {
@@ -82,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) {
@@ -111,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;
 
@@ -196,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;
@@ -233,17 +243,17 @@ static void mark_unreachable_referents(const struct object_id *oid)
 }
 
 static int mark_loose_unreachable_referents(const struct object_id *oid,
-                                           const char *path,
-                                           void *data)
+                                           const char *path UNUSED,
+                                           void *data UNUSED)
 {
        mark_unreachable_referents(oid);
        return 0;
 }
 
 static int mark_packed_unreachable_referents(const struct object_id *oid,
-                                            struct packed_git *pack,
-                                            uint32_t pos,
-                                            void *data)
+                                            struct packed_git *pack UNUSED,
+                                            uint32_t pos UNUSED,
+                                            void *data UNUSED)
 {
        mark_unreachable_referents(oid);
        return 0;
@@ -661,14 +671,15 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
        return 0; /* keep checking other objects, even if we saw an error */
 }
 
-static int fsck_cruft(const char *basename, const char *path, void *data)
+static int fsck_cruft(const char *basename, const char *path,
+                     void *data UNUSED)
 {
        if (!starts_with(basename, "tmp_obj_"))
                fprintf_ln(stderr, _("bad sha1 file: %s"), path);
        return 0;
 }
 
-static int fsck_subdir(unsigned int nr, const char *path, void *data)
+static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
 {
        struct for_each_loose_cb *cb_data = data;
        struct progress *progress = cb_data->progress;
@@ -732,19 +743,19 @@ static int fsck_head_link(const char *head_ref_name,
        return 0;
 }
 
-static int fsck_cache_tree(struct cache_tree *it)
+static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
 {
        int i;
        int err = 0;
 
        if (verbose)
-               fprintf_ln(stderr, _("Checking cache tree"));
+               fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
 
        if (0 <= it->entry_count) {
                struct object *obj = parse_object(the_repository, &it->oid);
                if (!obj) {
-                       error(_("%s: invalid sha1 pointer in cache-tree"),
-                             oid_to_hex(&it->oid));
+                       error(_("%s: invalid sha1 pointer in cache-tree of %s"),
+                             oid_to_hex(&it->oid), index_path);
                        errors_found |= ERROR_REFS;
                        return 1;
                }
@@ -755,11 +766,12 @@ static int fsck_cache_tree(struct cache_tree *it)
                        err |= objerror(obj, _("non-tree in cache-tree"));
        }
        for (i = 0; i < it->subtree_nr; i++)
-               err |= fsck_cache_tree(it->down[i]->cache_tree);
+               err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
        return err;
 }
 
-static int fsck_resolve_undo(struct index_state *istate)
+static int fsck_resolve_undo(struct index_state *istate,
+                            const char *index_path)
 {
        struct string_list_item *item;
        struct string_list *resolve_undo = istate->resolve_undo;
@@ -782,8 +794,9 @@ static int fsck_resolve_undo(struct index_state *istate)
 
                        obj = parse_object(the_repository, &ru->oid[i]);
                        if (!obj) {
-                               error(_("%s: invalid sha1 pointer in resolve-undo"),
-                                     oid_to_hex(&ru->oid[i]));
+                               error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
+                                     oid_to_hex(&ru->oid[i]),
+                                     index_path);
                                errors_found |= ERROR_REFS;
                                continue;
                        }
@@ -796,6 +809,38 @@ static int fsck_resolve_undo(struct index_state *istate)
        return 0;
 }
 
+static void fsck_index(struct index_state *istate, const char *index_path,
+                      int is_current_worktree)
+{
+       unsigned int i;
+
+       /* TODO: audit for interaction with sparse-index. */
+       ensure_full_index(istate);
+       for (i = 0; i < istate->cache_nr; i++) {
+               unsigned int mode;
+               struct blob *blob;
+               struct object *obj;
+
+               mode = istate->cache[i]->ce_mode;
+               if (S_ISGITLINK(mode))
+                       continue;
+               blob = lookup_blob(the_repository,
+                                  &istate->cache[i]->oid);
+               if (!blob)
+                       continue;
+               obj = &blob->object;
+               obj->flags |= USED;
+               fsck_put_object_name(&fsck_walk_options, &obj->oid,
+                                    "%s:%s",
+                                    is_current_worktree ? "" : index_path,
+                                    istate->cache[i]->name);
+               mark_object_reachable(obj);
+       }
+       if (istate->cache_tree)
+               fsck_cache_tree(istate->cache_tree, index_path);
+       fsck_resolve_undo(istate, index_path);
+}
+
 static void mark_object_for_connectivity(const struct object_id *oid)
 {
        struct object *obj = lookup_unknown_object(the_repository, oid);
@@ -803,22 +848,54 @@ static void mark_object_for_connectivity(const struct object_id *oid)
 }
 
 static int mark_loose_for_connectivity(const struct object_id *oid,
-                                      const char *path,
-                                      void *data)
+                                      const char *path UNUSED,
+                                      void *data UNUSED)
 {
        mark_object_for_connectivity(oid);
        return 0;
 }
 
 static int mark_packed_for_connectivity(const struct object_id *oid,
-                                       struct packed_git *pack,
-                                       uint32_t pos,
-                                       void *data)
+                                       struct packed_git *pack UNUSED,
+                                       uint32_t pos UNUSED,
+                                       void *data UNUSED)
 {
        mark_object_for_connectivity(oid);
        return 0;
 }
 
+static int check_pack_rev_indexes(struct repository *r, int show_progress)
+{
+       struct progress *progress = NULL;
+       uint32_t pack_count = 0;
+       int res = 0;
+
+       if (show_progress) {
+               for (struct packed_git *p = get_all_packs(r); p; p = p->next)
+                       pack_count++;
+               progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count);
+               pack_count = 0;
+       }
+
+       for (struct packed_git *p = get_all_packs(r); p; p = p->next) {
+               int load_error = load_pack_revindex_from_disk(p);
+
+               if (load_error < 0) {
+                       error(_("unable to load rev-index for pack '%s'"), p->pack_name);
+                       res = ERROR_PACK_REV_INDEX;
+               } else if (!load_error &&
+                          !load_pack_revindex(r, p) &&
+                          verify_pack_revindex(p)) {
+                       error(_("invalid rev-index for pack '%s'"), p->pack_name);
+                       res = ERROR_PACK_REV_INDEX;
+               }
+               display_progress(progress, ++pack_count);
+       }
+       stop_progress(&progress);
+
+       return res;
+}
+
 static char const * const fsck_usage[] = {
        N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
           "         [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
@@ -854,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);
@@ -923,7 +1000,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
                struct object_id oid;
-               if (!get_oid(arg, &oid)) {
+               if (!repo_get_oid(the_repository, arg, &oid)) {
                        struct object *obj = lookup_object(the_repository,
                                                           &oid);
 
@@ -956,34 +1033,36 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        }
 
        if (keep_cache_objects) {
+               struct worktree **worktrees, **p;
+
                verify_index_checksum = 1;
                verify_ce_order = 1;
-               repo_read_index(the_repository);
-               /* TODO: audit for interaction with sparse-index. */
-               ensure_full_index(&the_index);
-               for (i = 0; i < the_index.cache_nr; i++) {
-                       unsigned int mode;
-                       struct blob *blob;
-                       struct object *obj;
 
-                       mode = the_index.cache[i]->ce_mode;
-                       if (S_ISGITLINK(mode))
-                               continue;
-                       blob = lookup_blob(the_repository,
-                                          &the_index.cache[i]->oid);
-                       if (!blob)
-                               continue;
-                       obj = &blob->object;
-                       obj->flags |= USED;
-                       fsck_put_object_name(&fsck_walk_options, &obj->oid,
-                                            ":%s", the_index.cache[i]->name);
-                       mark_object_reachable(obj);
+               worktrees = get_worktrees();
+               for (p = worktrees; *p; p++) {
+                       struct worktree *wt = *p;
+                       struct index_state istate =
+                               INDEX_STATE_INIT(the_repository);
+                       char *path;
+
+                       /*
+                        * Make a copy since the buffer is reusable
+                        * and may get overwritten by other calls
+                        * while we're examining the index.
+                        */
+                       path = xstrdup(worktree_git_path(wt, "index"));
+                       read_index_from(&istate, path, get_worktree_git_dir(wt));
+                       fsck_index(&istate, path, wt->is_current);
+                       discard_index(&istate);
+                       free(path);
                }
-               if (the_index.cache_tree)
-                       fsck_cache_tree(the_index.cache_tree);
-               fsck_resolve_undo(&the_index);
+               free_worktrees(worktrees);
        }
 
+       errors_found |= check_pack_rev_indexes(the_repository, show_progress);
+       if (verify_bitmap_files(the_repository))
+               errors_found |= ERROR_BITMAP;
+
        check_connectivity();
 
        if (the_repository->settings.core_commit_graph) {
@@ -995,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;
                }
@@ -1009,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 0feef8caf6d5e27d508b3d4ea3e2679cd50a9966..7e99c4d61ba95942014d8ab2681568f53658fd0d 100644 (file)
@@ -1,15 +1,21 @@
 #include "builtin.h"
+#include "abspath.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[] = {
        N_("git fsmonitor--daemon start [<options>]"),
@@ -32,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);
@@ -44,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);
@@ -54,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);
@@ -62,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);
 }
 
 /*
@@ -1574,7 +1581,7 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
 }
 
 #else
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED)
 {
        struct option options[] = {
                OPT_END()
index 02455fdcd73603ad640a7a54c697c7d7f58225cf..719cae9a88aa0168ce4023434232c9d186d27271 100644 (file)
  */
 
 #include "builtin.h"
+#include "abspath.h"
+#include "date.h"
+#include "environment.h"
+#include "hex.h"
 #include "repository.h"
 #include "config.h"
 #include "tempfile.h"
 #include "commit.h"
 #include "commit-graph.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.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"
 #include "refs.h"
 #include "remote.h"
 #include "exec-cmd.h"
+#include "gettext.h"
 #include "hook.h"
+#include "setup.h"
+#include "trace2.h"
 
 #define FAILED_RUN "failed to run %s"
 
@@ -42,7 +51,7 @@ static const char * const builtin_gc_usage[] = {
 
 static int pack_refs = 1;
 static int prune_reflogs = 1;
-static int cruft_packs = -1;
+static int cruft_packs = 1;
 static int aggressive_depth = 50;
 static int aggressive_window = 250;
 static int gc_auto_threshold = 6700;
@@ -213,7 +222,7 @@ static struct packed_git *find_base_packs(struct string_list *packs,
        struct packed_git *p, *base = NULL;
 
        for (p = get_all_packs(the_repository); p; p = p->next) {
-               if (!p->pack_local)
+               if (!p->pack_local || p->is_cruft)
                        continue;
                if (limit) {
                        if (p->pack_size >= limit)
@@ -284,7 +293,7 @@ static uint64_t total_ram(void)
 
 static uint64_t estimate_repack_memory(struct packed_git *pack)
 {
-       unsigned long nr_objects = approximate_object_count();
+       unsigned long nr_objects = repo_approximate_object_count(the_repository);
        size_t os_cache, heap;
 
        if (!pack || !nr_objects)
@@ -602,10 +611,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        if (prune_expire && parse_expiry_date(prune_expire, &dummy))
                die(_("failed to parse prune expiry value %s"), prune_expire);
 
-       prepare_repo_settings(the_repository);
-       if (cruft_packs < 0)
-               cruft_packs = the_repository->settings.gc_cruft_packs;
-
        if (aggressive) {
                strvec_push(&repack, "-f");
                if (aggressive_depth > 0)
@@ -699,7 +704,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                        strvec_push(&prune, prune_expire);
                        if (quiet)
                                strvec_push(&prune, "--no-progress");
-                       if (has_promisor_remote())
+                       if (repo_has_promisor_remote(the_repository))
                                strvec_push(&prune,
                                            "--exclude-promisor-objects");
                        prune_cmd.git_cmd = 1;
@@ -820,7 +825,7 @@ static int dfs_on_ref(const char *refname UNUSED,
        commit = lookup_commit(the_repository, oid);
        if (!commit)
                return 0;
-       if (parse_commit(commit) ||
+       if (repo_parse_commit(the_repository, commit) ||
            commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
                return 0;
 
@@ -837,7 +842,7 @@ static int dfs_on_ref(const char *refname UNUSED,
                commit = pop_commit(&stack);
 
                for (parent = commit->parents; parent; parent = parent->next) {
-                       if (parse_commit(parent->item) ||
+                       if (repo_parse_commit(the_repository, parent->item) ||
                            commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
                            parent->item->object.flags & SEEN)
                                continue;
@@ -976,9 +981,9 @@ struct write_loose_object_data {
 
 static int loose_object_auto_limit = 100;
 
-static int loose_object_count(const struct object_id *oid,
-                              const char *path,
-                              void *data)
+static int loose_object_count(const struct object_id *oid UNUSED,
+                             const char *path UNUSED,
+                             void *data)
 {
        int *count = (int*)data;
        if (++(*count) >= loose_object_auto_limit)
@@ -1003,15 +1008,15 @@ static int loose_object_auto_condition(void)
                                             NULL, NULL, &count);
 }
 
-static int bail_on_loose(const struct object_id *oid,
-                        const char *path,
-                        void *data)
+static int bail_on_loose(const struct object_id *oid UNUSED,
+                        const char *path UNUSED,
+                        void *data UNUSED)
 {
        return 1;
 }
 
 static int write_loose_object_to_stdin(const struct object_id *oid,
-                                      const char *path,
+                                      const char *path UNUSED,
                                       void *data)
 {
        struct write_loose_object_data *d = (struct write_loose_object_data *)data;
@@ -1493,7 +1498,6 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
        };
        int found = 0;
        const char *key = "maintenance.repo";
-       char *config_value;
        char *maintpath = get_maintpath();
        struct string_list_item *item;
        const struct string_list *list;
@@ -1508,13 +1512,10 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
        git_config_set("maintenance.auto", "false");
 
        /* Set maintenance strategy, if unset */
-       if (!git_config_get_string("maintenance.strategy", &config_value))
-               free(config_value);
-       else
+       if (git_config_get("maintenance.strategy"))
                git_config_set("maintenance.strategy", "incremental");
 
-       list = git_config_get_value_multi(key);
-       if (list) {
+       if (!git_config_get_string_multi(key, &list)) {
                for_each_string_list_item(item, list) {
                        if (!strcmp(maintpath, item->string)) {
                                found = 1;
@@ -1580,11 +1581,10 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
        if (config_file) {
                git_configset_init(&cs);
                git_configset_add_file(&cs, config_file);
-               list = git_configset_get_value_multi(&cs, key);
-       } else {
-               list = git_config_get_value_multi(key);
        }
-       if (list) {
+       if (!(config_file
+             ? git_configset_get_string_multi(&cs, key, &list)
+             : git_config_get_string_multi(key, &list))) {
                for_each_string_list_item(item, list) {
                        if (!strcmp(maintpath, item->string)) {
                                found = 1;
@@ -1686,11 +1686,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
        if (is_available)
                *is_available = 0;
 
-       string_list_split_in_place(&list, testing, ',', -1);
+       string_list_split_in_place(&list, testing, ",", -1);
        for_each_string_list_item(item, &list) {
                struct string_list pair = STRING_LIST_INIT_NODUP;
 
-               if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
+               if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
                        continue;
 
                if (!strcmp(*cmd, pair.items[0].string)) {
@@ -2068,7 +2068,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"
@@ -2397,7 +2397,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"
index 491af9202dc937339db83980e2bf96de6ff81646..20d0dfe9cf1dfefe6ffacb23bd500701cca71a09 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * Copyright (c) 2005, 2006 Rene Scharfe
  */
-#include "cache.h"
+#include "builtin.h"
 #include "commit.h"
 #include "tar.h"
-#include "builtin.h"
 #include "quote.h"
 
 static const char builtin_get_tar_commit_id_usage[] =
@@ -14,7 +13,7 @@ static const char builtin_get_tar_commit_id_usage[] =
 #define RECORDSIZE     (512)
 #define HEADERSIZE (2 * RECORDSIZE)
 
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
+int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix)
 {
        char buffer[HEADERSIZE];
        struct ustar_header *header = (struct ustar_header *)buffer;
@@ -24,6 +23,8 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
        long len;
        char *end;
 
+       BUG_ON_NON_EMPTY_PREFIX(prefix);
+
        if (argc != 1)
                usage(builtin_get_tar_commit_id_usage);
 
@@ -32,7 +33,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
                die_errno("git get-tar-commit-id: read error");
        if (n != HEADERSIZE)
                die_errno("git get-tar-commit-id: EOF before reading tar header");
-       if (header->typeflag[0] != 'g')
+       if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER)
                return 1;
 
        len = strtol(content, &end, 10);
index f7821c5fbbaeda3888f3011ee5215393e1319952..2a261074f16c4be5c9c8e3e3ec11a8e1aecebfa3 100644 (file)
@@ -3,7 +3,9 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
-#include "cache.h"
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "config.h"
 #include "blob.h"
@@ -11,7 +13,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 "quote.h"
 #include "dir.h"
 #include "pathspec.h"
+#include "setup.h"
 #include "submodule.h"
 #include "submodule-config.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.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;
 
@@ -282,14 +290,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);
@@ -560,7 +572,8 @@ static int grep_cache(struct grep_opt *opt,
                        void *data;
                        unsigned long size;
 
-                       data = read_object_file(&ce->oid, &type, &size);
+                       data = repo_read_object_file(the_repository, &ce->oid,
+                                                    &type, &size);
                        init_tree_desc(&tree, data, size);
 
                        hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
@@ -630,7 +643,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)
@@ -650,7 +663,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                        void *data;
                        unsigned long size;
 
-                       data = read_object_file(&entry.oid, &type, &size);
+                       data = repo_read_object_file(the_repository,
+                                                    &entry.oid, &type, &size);
                        if (!data)
                                die(_("unable to read tree (%s)"),
                                    oid_to_hex(&entry.oid));
@@ -976,7 +990,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 44db83f07fd12c535d758f596b6b12f20b7eeb2e..5ffec99dceaf5c95d9b57c1f0c6c90358b80507d 100644 (file)
@@ -5,12 +5,19 @@
  * Copyright (C) Junio C Hamano, 2005
  */
 #include "builtin.h"
+#include "abspath.h"
 #include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.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"
 
 /*
  * This is to create corrupt objects for debugging and as such it
index 53f2812dfb1c935fed6b25570f99f13fcfa67f15..dc1fbe2b9862df507dc1e077258d3c44048eebef 100644 (file)
@@ -1,15 +1,18 @@
 /*
  * 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"
 #include "parse-options.h"
+#include "path.h"
 #include "run-command.h"
 #include "config-list.h"
 #include "help.h"
 #include "alias.h"
+#include "setup.h"
 
 #ifndef DEFAULT_HELP_FORMAT
 #define DEFAULT_HELP_FORMAT "man"
@@ -394,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)
@@ -417,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 f95b7965c58efe779d91a60d2b91b36742ac31f7..09b51a6487c3928bc099567109193c32fe82fe30 100644 (file)
@@ -1,6 +1,6 @@
-#include "cache.h"
 #include "builtin.h"
 #include "config.h"
+#include "gettext.h"
 #include "hook.h"
 #include "parse-options.h"
 #include "strbuf.h"
index 6648f2daef5cef38fd59dfba47c048ce72bb4c36..006ffdc9c550d75a034960635f13d87b33dc57cc 100644 (file)
@@ -1,6 +1,9 @@
 #include "builtin.h"
 #include "config.h"
 #include "delta.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "pack.h"
 #include "csum-file.h"
 #include "blob.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 "object-store.h"
+#include "pack-revindex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "replace-object.h"
 #include "promisor-remote.h"
+#include "setup.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>])";
@@ -212,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;
@@ -801,7 +811,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
        if (startup_info->have_repository) {
                read_lock();
                collision_test_needed =
-                       has_object_file_with_flags(oid, OBJECT_INFO_QUICK);
+                       repo_has_object_file_with_flags(the_repository, oid,
+                                                       OBJECT_INFO_QUICK);
                read_unlock();
        }
 
@@ -821,7 +832,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        die(_("cannot read existing object info %s"), oid_to_hex(oid));
                if (has_type != type || has_size != size)
                        die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
-               has_data = read_object_file(oid, &has_type, &has_size);
+               has_data = repo_read_object_file(the_repository, oid,
+                                                &has_type, &has_size);
                read_unlock();
                if (!data)
                        data = new_data = get_data_from_pack(obj_entry);
@@ -1388,7 +1400,7 @@ static void fix_unresolved_deltas(struct hashfile *f)
                sorted_by_pos[i] = &ref_deltas[i];
        QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
 
-       if (has_promisor_remote()) {
+       if (repo_has_promisor_remote(the_repository)) {
                /*
                 * Prefetch the delta bases.
                 */
@@ -1414,7 +1426,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
 
                if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
                        continue;
-               data = read_object_file(&d->oid, &type, &size);
+               data = repo_read_object_file(the_repository, &d->oid, &type,
+                                            &size);
                if (!data)
                        continue;
 
@@ -1568,18 +1581,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);
@@ -1595,7 +1609,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_)
@@ -1739,16 +1753,17 @@ 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);
+       opts.flags |= WRITE_REV;
        git_config(git_index_pack_config, &opts);
        if (prefix && chdir(prefix))
                die(_("Cannot come back to cwd"));
 
-       if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
-               rev_index = 1;
+       if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+               rev_index = 0;
        else
                rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
 
index dcaaf102eaf62bee5d09adabd2a5de21c8379c03..cb727c826f5653ab2827ccfbd575e6d305fad75a 100644 (file)
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
-#include "config.h"
-#include "refs.h"
 #include "builtin.h"
-#include "exec-cmd.h"
+#include "abspath.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
 #include "parse-options.h"
-#include "worktree.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 "path.h"
+#include "setup.h"
+#include "strbuf.h"
 
 static int guess_repository_type(const char *git_dir)
 {
@@ -538,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")),
@@ -695,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 e58627c72a98510f12b0a8494432e44a6ccfad2e..c5e83452654de9242f01a4045fb90f3f058ea8f7 100644 (file)
@@ -5,8 +5,8 @@
  *
  */
 
-#include "cache.h"
 #include "builtin.h"
+#include "gettext.h"
 #include "parse-options.h"
 #include "string-list.h"
 #include "trailer.h"
index a70fba198f9451c9005b3ecd14cfce8765e1d838..5d808c92f441523f729e5edcdc3370d09f8bafdc 100644 (file)
@@ -4,10 +4,17 @@
  * (C) Copyright 2006 Linus Torvalds
  *              2006 Junio Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
 #include "color.h"
 #include "commit.h"
 #include "diff.h"
@@ -15,6 +22,7 @@
 #include "revision.h"
 #include "log-tree.h"
 #include "builtin.h"
+#include "oid-array.h"
 #include "tag.h"
 #include "reflog-walk.h"
 #include "patch-ids.h"
@@ -35,6 +43,8 @@
 #include "commit-reach.h"
 #include "range-diff.h"
 #include "tmp-objdir.h"
+#include "tree.h"
+#include "write-or-die.h"
 
 #define MAIL_DEFAULT_WRAP 72
 #define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
@@ -56,6 +66,7 @@ static int stdout_mboxrd;
 static const char *fmt_patch_subject_prefix = "PATCH";
 static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
 static const char *fmt_pretty;
+static int format_no_prefix;
 
 static const char * const builtin_log_usage[] = {
        N_("git log [<options>] [<revision-range>] [[--] <path>...]"),
@@ -182,10 +193,10 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
        int i;
        char *value = NULL;
        struct string_list *include = decoration_filter->include_ref_pattern;
-       const struct string_list *config_exclude =
-                       git_config_get_value_multi("log.excludeDecoration");
+       const struct string_list *config_exclude;
 
-       if (config_exclude) {
+       if (!git_config_get_string_multi("log.excludeDecoration",
+                                        &config_exclude)) {
                struct string_list_item *item;
                for_each_string_list_item(item, config_exclude)
                        string_list_append(decoration_filter->exclude_ref_config_pattern,
@@ -436,7 +447,7 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
        setitimer(ITIMER_REAL, &early_output_timer, NULL);
 }
 
-static void early_output(int signal)
+static void early_output(int signal UNUSED)
 {
        show_early_output = log_show_early;
 }
@@ -538,7 +549,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)
@@ -552,7 +563,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;
 
@@ -561,7 +573,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")) {
@@ -601,9 +613,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (git_gpg_config(var, value, cb) < 0)
-               return -1;
-       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)
@@ -675,7 +685,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 {
        unsigned long size;
        enum object_type type;
-       char *buf = read_object_file(oid, &type, &size);
+       char *buf = repo_read_object_file(the_repository, oid, &type, &size);
        int offset = 0;
 
        if (!buf)
@@ -708,8 +718,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);
@@ -852,11 +861,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)
@@ -969,7 +977,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)
@@ -1084,8 +1093,21 @@ static int git_format_config(const char *var, const char *value, void *cb)
                stdout_mboxrd = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "format.noprefix")) {
+               format_no_prefix = 1;
+               return 0;
+       }
 
-       return git_log_config(var, value, cb);
+       /*
+        * ignore some porcelain config which would otherwise be parsed by
+        * git_diff_ui_config(), via git_log_config(); we can't just avoid
+        * diff_ui_config completely, because we do care about some ui options
+        * like color.
+        */
+       if (!strcmp(var, "diff.noprefix"))
+               return 0;
+
+       return git_log_config(var, value, ctx, cb);
 }
 
 static const char *output_directory = NULL;
@@ -1204,7 +1226,8 @@ static char *find_branch_name(struct rev_info *rev)
                return NULL;
        ref = rev->cmdline.rev[positive].name;
        tip_oid = &rev->cmdline.rev[positive].item->oid;
-       if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref, 0) &&
+       if (repo_dwim_ref(the_repository, ref, strlen(ref), &branch_oid,
+                         &full_ref, 0) &&
            skip_prefix(full_ref, "refs/heads/", &v) &&
            oideq(tip_oid, &branch_oid))
                branch = xstrdup(v);
@@ -1314,10 +1337,11 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
        log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
 
        for (i = 0; !need_8bit_cte && i < nr; i++) {
-               const char *buf = get_commit_buffer(list[i], NULL);
+               const char *buf = repo_get_commit_buffer(the_repository,
+                                                        list[i], NULL);
                if (has_non_ascii(buf))
                        need_8bit_cte = 1;
-               unuse_commit_buffer(list[i], buf);
+               repo_unuse_commit_buffer(the_repository, list[i], buf);
        }
 
        if (!branch_name)
@@ -1370,7 +1394,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
                        .other_arg = &other_arg
                };
 
-               diff_setup(&opts);
+               repo_diff_setup(the_repository, &opts);
                opts.file = rev->diffopt.file;
                opts.use_color = rev->diffopt.use_color;
                diff_setup_done(&opts);
@@ -1381,7 +1405,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;
@@ -1399,7 +1423,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);
 }
 
@@ -1642,14 +1666,16 @@ static struct commit *get_base_commit(const char *base_commit,
                        struct commit *commit;
                        struct object_id oid;
 
-                       if (get_oid(upstream, &oid)) {
+                       if (repo_get_oid(the_repository, upstream, &oid)) {
                                if (die_on_failure)
                                        die(_("failed to resolve '%s' as a valid ref"), upstream);
                                else
                                        return NULL;
                        }
                        commit = lookup_commit_or_die(&oid, "upstream base");
-                       base_list = get_merge_bases_many(commit, total, list);
+                       base_list = repo_get_merge_bases_many(the_repository,
+                                                             commit, total,
+                                                             list);
                        /* There should be one and only one merge base. */
                        if (!base_list || base_list->next) {
                                if (die_on_failure) {
@@ -1683,7 +1709,9 @@ static struct commit *get_base_commit(const char *base_commit,
        while (rev_nr > 1) {
                for (i = 0; i < rev_nr / 2; i++) {
                        struct commit_list *merge_base;
-                       merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]);
+                       merge_base = repo_get_merge_bases(the_repository,
+                                                         rev[2 * i],
+                                                         rev[2 * i + 1]);
                        if (!merge_base || merge_base->next) {
                                if (die_on_failure) {
                                        die(_("failed to find exact merge base"));
@@ -1701,7 +1729,7 @@ static struct commit *get_base_commit(const char *base_commit,
                rev_nr = DIV_ROUND_UP(rev_nr, 2);
        }
 
-       if (!in_merge_bases(base, rev[0])) {
+       if (!repo_in_merge_bases(the_repository, base, rev[0])) {
                if (die_on_failure) {
                        die(_("base commit should be the ancestor of revision list"));
                } else {
@@ -1993,6 +2021,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        s_r_opt.def = "HEAD";
        s_r_opt.revarg_opt = REVARG_COMMITTISH;
 
+       if (format_no_prefix)
+               diff_set_noprefix(&rev.diffopt);
+
        if (default_attach) {
                rev.mime_boundary = default_attach;
                rev.no_inline = 1;
@@ -2097,6 +2128,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
        /* Always generate a patch */
        rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+       rev.always_show_header = 1;
 
        rev.zero_commit = zero_commit;
        rev.patch_name_max = fmt_patch_name_max;
@@ -2277,11 +2309,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;
@@ -2337,8 +2369,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));
                }
@@ -2387,6 +2419,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);
@@ -2396,7 +2429,7 @@ done:
 static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
 {
        struct object_id oid;
-       if (get_oid(arg, &oid) == 0) {
+       if (repo_get_oid(the_repository, arg, &oid) == 0) {
                struct commit *commit = lookup_commit_reference(the_repository,
                                                                &oid);
                if (commit) {
@@ -2418,12 +2451,12 @@ static void print_commit(char sign, struct commit *commit, int verbose,
 {
        if (!verbose) {
                fprintf(file, "%c %s\n", sign,
-                      find_unique_abbrev(&commit->object.oid, abbrev));
+                      repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev));
        } else {
                struct strbuf buf = STRBUF_INIT;
                pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
                fprintf(file, "%c %s %s\n", sign,
-                      find_unique_abbrev(&commit->object.oid, abbrev),
+                      repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev),
                       buf.buf);
                strbuf_release(&buf);
        }
index a03b559ecaab4caeba9a9a18bb268f22274e7b2a..a0229c3277874accc9edf0a4a5ac4e8186217903 100644 (file)
@@ -5,22 +5,31 @@
  *
  * 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 "tree.h"
 #include "cache-tree.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;
@@ -89,12 +98,15 @@ static void write_name(const char *name)
 
 static void write_name_to_buf(struct strbuf *sb, const char *name)
 {
-       const char *rel = relative_path(name, prefix_len ? prefix : NULL, sb);
+       struct strbuf buf = STRBUF_INIT;
+       const char *rel = relative_path(name, prefix_len ? prefix : NULL, &buf);
 
        if (line_terminator)
                quote_c_style(rel, sb, NULL, 0);
        else
                strbuf_addstr(sb, rel);
+
+       strbuf_release(&buf);
 }
 
 static const char *get_tag(const struct cache_entry *ce, const char *tag)
@@ -234,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);
@@ -360,7 +379,7 @@ static void show_ru_info(struct index_state *istate)
                        if (!ui->mode[i])
                                continue;
                        printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
-                              find_unique_abbrev(&ui->oid[i], abbrev),
+                              repo_find_unique_abbrev(the_repository, &ui->oid[i], abbrev),
                               i + 1);
                        write_name(path);
                }
@@ -509,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 (get_oid(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 6516177348996cd6e73d69e5c3884e53e6dfda73..fc765754305ed7a3f8a2efdcd604dd29c8b3b502 100644 (file)
@@ -1,9 +1,13 @@
 #include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
 #include "transport.h"
+#include "pkt-line.h"
 #include "ref-filter.h"
 #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 8cc8c995df9399cd84465060965d065d33cd5d3b..f558db5f3b80b3d72f5f66f008e3fa2072c2e8ed 100644 (file)
@@ -3,14 +3,17 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.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"
 
@@ -47,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)
 {
@@ -147,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;
@@ -163,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);
@@ -195,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);
 
@@ -228,7 +204,7 @@ static int show_tree_default(const struct object_id *oid, struct strbuf *base,
                return early;
 
        printf("%06o %s %s\t", mode, type_name(object_type(mode)),
-              find_unique_abbrev(oid, options->abbrev));
+              repo_find_unique_abbrev(the_repository, oid, options->abbrev));
        show_tree_common_default_long(options, base, pathname, base->len);
        return recurse;
 }
@@ -259,7 +235,8 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
        }
 
        printf("%06o %s %s %7s\t", mode, type_name(type),
-              find_unique_abbrev(oid, options->abbrev), size_text);
+              repo_find_unique_abbrev(the_repository, oid, options->abbrev),
+              size_text);
        show_tree_common_default_long(options, base, pathname, base->len);
        return recurse;
 }
@@ -279,7 +256,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;
@@ -310,7 +287,7 @@ static int show_tree_object(const struct object_id *oid, struct strbuf *base,
        if (early >= 0)
                return early;
 
-       str = find_unique_abbrev(oid, options->abbrev);
+       str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
        if (options->null_termination) {
                fputs(str, stdout);
                fputc('\0', stdout);
@@ -366,6 +343,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;
@@ -387,8 +365,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)")),
@@ -402,18 +379,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
@@ -433,7 +407,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                        ls_tree_usage, ls_tree_options);
        if (argc < 1)
                usage_with_options(ls_tree_usage, ls_tree_options);
-       if (get_oid(argv[0], &oid))
+       if (repo_get_oid(the_repository, argv[0], &oid))
                die("Not a valid object name %s", argv[0]);
 
        /*
index 01d16ef9e5a2d696130eab00fd1aaa58116599d3..53b55dd71c0537b149860c4b9c0d505ea305fe57 100644 (file)
@@ -2,8 +2,10 @@
  * Another stupid program, this one parsing the headers of an
  * email to figure out authorship and subject
  */
-#include "cache.h"
 #include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
 #include "utf8.h"
 #include "strbuf.h"
 #include "mailinfo.h"
index 73509f651bda4805e8399d75eda80ec8976bda07..3af9ddb8ae5c7e902937ada927590d908c193e0f 100644 (file)
@@ -4,8 +4,8 @@
  * 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"
 #include "strbuf.h"
 
@@ -277,6 +277,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
        const char **argp;
        static const char *stdin_only[] = { "-", NULL };
 
+       BUG_ON_NON_EMPTY_PREFIX(prefix);
+
        for (argp = argv+1; *argp; argp++) {
                const char *arg = *argp;
 
index 6f3941f2a49ce51ee295158a4d78f5c80c1afeb7..e68b7fe45d77a9b032dd6031864b876eeeca5e5c 100644 (file)
@@ -1,10 +1,12 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "commit.h"
+#include "gettext.h"
+#include "hex.h"
 #include "refs.h"
 #include "diff.h"
 #include "revision.h"
+#include "object-name.h"
 #include "parse-options.h"
 #include "repository.h"
 #include "commit-reach.h"
@@ -13,7 +15,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 {
        struct commit_list *result, *r;
 
-       result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
+       result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
+                                                rev_nr - 1, rev + 1);
 
        if (!result)
                return 1;
@@ -42,7 +45,7 @@ static struct commit *get_commit_reference(const char *arg)
        struct object_id revkey;
        struct commit *r;
 
-       if (get_oid(arg, &revkey))
+       if (repo_get_oid(the_repository, arg, &revkey))
                die("Not a valid object name %s", arg);
        r = lookup_commit_reference(the_repository, &revkey);
        if (!r)
@@ -105,7 +108,7 @@ static int handle_is_ancestor(int argc, const char **argv)
                die("--is-ancestor takes exactly two commits");
        one = get_commit_reference(argv[0]);
        two = get_commit_reference(argv[1]);
-       if (in_merge_bases(one, two))
+       if (repo_in_merge_bases(the_repository, one, two))
                return 0;
        else
                return 1;
@@ -118,7 +121,7 @@ static int handle_fork_point(int argc, const char **argv)
        const char *commitname;
 
        commitname = (argc == 2) ? argv[1] : "HEAD";
-       if (get_oid(commitname, &oid))
+       if (repo_get_oid(the_repository, commitname, &oid))
                die("Not a valid object name: '%s'", commitname);
 
        derived = lookup_commit_reference(the_repository, &oid);
index c923bbf2abbdfa9d8a5461fcf5c0402a341a061b..d7eb4c654018e2bf8270ba90f1a3d945a261d025 100644 (file)
@@ -1,6 +1,8 @@
 #include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
 #include "config.h"
+#include "gettext.h"
+#include "setup.h"
 #include "xdiff/xdiff.h"
 #include "xdiff-interface.h"
 #include "parse-options.h"
index 452f833ac4610121d5194a65087d733e4b66914f..270d5f644ac22e1a8a1b43b282b9ebf0f5cb12b0 100644 (file)
@@ -1,6 +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;
@@ -70,7 +74,7 @@ static void merge_all(void)
        }
 }
 
-int cmd_merge_index(int argc, const char **argv, const char *prefix)
+int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED)
 {
        int i, force_file = 0;
 
index 284eb48609837e66d4511ecb7fb3cc89dfbf8b90..932924e5d0e573959e2d8c70168f77224de45bc8 100644 (file)
 #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>...";
 
-int cmd_merge_ours(int argc, const char **argv, const char *prefix)
+int cmd_merge_ours(int argc, const char **argv, const char *prefix UNUSED)
 {
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(builtin_merge_ours_usage);
index b9acbf5d3427e7dd88533351db5d2fc245cc25f6..3366699657c9c390f850dfcba11be08327834f50 100644 (file)
@@ -1,8 +1,12 @@
-#include "cache.h"
 #include "builtin.h"
+#include "advice.h"
 #include "commit.h"
+#include "gettext.h"
+#include "hash.h"
 #include "tag.h"
 #include "merge-recursive.h"
+#include "object-name.h"
+#include "repository.h"
 #include "xdiff-interface.h"
 
 static const char builtin_merge_recursive_usage[] =
@@ -20,7 +24,7 @@ static char *better_branch_name(const char *branch)
        return xstrdup(name ? name : branch);
 }
 
-int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
+int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
 {
        const struct object_id *bases[21];
        unsigned bases_count = 0;
@@ -49,7 +53,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
                }
                if (bases_count < ARRAY_SIZE(bases)-1) {
                        struct object_id *oid = xmalloc(sizeof(struct object_id));
-                       if (get_oid(argv[i], oid))
+                       if (repo_get_oid(the_repository, argv[i], oid))
                                die(_("could not parse object '%s'"), argv[i]);
                        bases[bases_count++] = oid;
                }
@@ -70,9 +74,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
        o.branch1 = argv[++i];
        o.branch2 = argv[++i];
 
-       if (get_oid(o.branch1, &h1))
+       if (repo_get_oid(the_repository, o.branch1, &h1))
                die(_("could not resolve ref '%s'"), o.branch1);
-       if (get_oid(o.branch2, &h2))
+       if (repo_get_oid(the_repository, o.branch2, &h2))
                die(_("could not resolve ref '%s'"), o.branch2);
 
        o.branch1 = better1 = better_branch_name(o.branch1);
index 828dc81c426514d822e6bbce172495373f9a92c5..0de42aecf4babf5d1cae19aa81e7d46676c636d1 100644 (file)
@@ -3,16 +3,21 @@
 #include "tree-walk.h"
 #include "xdiff-interface.h"
 #include "help.h"
+#include "gettext.h"
+#include "hex.h"
 #include "commit.h"
 #include "commit-reach.h"
 #include "merge-ort.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "parse-options.h"
 #include "repository.h"
 #include "blob.h"
 #include "exec-cmd.h"
 #include "merge-blobs.h"
 #include "quote.h"
+#include "tree.h"
+#include "config.h"
 
 static int line_termination = '\n';
 
@@ -69,7 +74,9 @@ static void *result(struct merge_list *entry, unsigned long *size)
        const char *path = entry->path;
 
        if (!entry->stage)
-               return read_object_file(&entry->blob->object.oid, &type, size);
+               return repo_read_object_file(the_repository,
+                                            &entry->blob->object.oid, &type,
+                                            size);
        base = NULL;
        if (entry->stage == 1) {
                base = entry->blob;
@@ -92,8 +99,9 @@ static void *origin(struct merge_list *entry, unsigned long *size)
        enum object_type type;
        while (entry) {
                if (entry->stage == 2)
-                       return read_object_file(&entry->blob->object.oid,
-                                               &type, size);
+                       return repo_read_object_file(the_repository,
+                                                    &entry->blob->object.oid,
+                                                    &type, size);
                entry = entry->link;
        }
        return NULL;
@@ -316,7 +324,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)) {
@@ -440,19 +450,20 @@ 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 = get_commit_tree(base_commit);
-               parent1_tree = get_commit_tree(parent1);
-               parent2_tree = get_commit_tree(parent2);
+               base_tree = repo_get_commit_tree(the_repository, base_commit);
+               parent1_tree = repo_get_commit_tree(the_repository, parent1);
+               parent2_tree = repo_get_commit_tree(the_repository, parent2);
                merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
        } else {
                /*
                 * Get the merge bases, in reverse order; see comment above
                 * merge_incore_recursive in merge-ort.h
                 */
-               merge_bases = get_merge_bases(parent1, parent2);
+               merge_bases = repo_get_merge_bases(the_repository, parent1,
+                                                  parent2);
                if (!merge_bases && !o->allow_unrelated_histories)
                        die(_("refusing to merge unrelated histories"));
                merge_bases = reverse_commit_list(merge_bases);
@@ -620,6 +631,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
        if (argc != expected_remaining_argc)
                usage_with_options(merge_tree_usage, mt_options);
 
+       git_config(git_default_config, NULL);
+
        /* Do the relevant type of merge */
        if (o.mode == MODE_REAL)
                return real_merge(&o, merge_base, argv[0], argv[1], prefix);
index 0a3c10a0966bdfc8f354cffb19d8f27987298600..de68910177fbff00d19a0f8ef824776de0458636 100644 (file)
@@ -7,10 +7,16 @@
  */
 
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
 #include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
 #include "parse-options.h"
-#include "builtin.h"
 #include "lockfile.h"
 #include "run-command.h"
 #include "hook.h"
@@ -20,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"
@@ -29,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"
@@ -337,7 +345,7 @@ static int save_state(struct object_id *stash)
        else if (!len)          /* no changes */
                goto out;
        strbuf_setlen(&buffer, buffer.len-1);
-       if (get_oid(buffer.buf, stash))
+       if (repo_get_oid(the_repository, buffer.buf, stash))
                die(_("not a valid object: %s"), buffer.buf);
        rc = 0;
 out:
@@ -517,7 +525,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
        if (!remote_head)
                die(_("'%s' does not point to a commit"), remote);
 
-       if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref, 0) > 0) {
+       if (repo_dwim_ref(the_repository, remote, strlen(remote), &branch_head,
+                         &found_ref, 0) > 0) {
                if (starts_with(found_ref, "refs/heads/")) {
                        strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
                                    oid_to_hex(&branch_head), remote);
@@ -613,7 +622,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;
@@ -658,13 +668,10 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return 0;
        }
 
-       status = fmt_merge_msg_config(k, v, cb);
-       if (status)
-               return status;
-       status = git_gpg_config(k, v, NULL);
+       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,
@@ -872,13 +879,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)
@@ -1531,7 +1540,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (!remoteheads)
                ; /* already up-to-date */
        else if (!remoteheads->next)
-               common = get_merge_bases(head_commit, remoteheads->item);
+               common = repo_get_merge_bases(the_repository, head_commit,
+                                             remoteheads->item);
        else {
                struct commit_list *list = remoteheads;
                commit_list_insert(head_commit, &list);
@@ -1567,10 +1577,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
                if (verbosity >= 0) {
                        printf(_("Updating %s..%s\n"),
-                              find_unique_abbrev(&head_commit->object.oid,
-                                                 DEFAULT_ABBREV),
-                              find_unique_abbrev(&remoteheads->item->object.oid,
-                                                 DEFAULT_ABBREV));
+                              repo_find_unique_abbrev(the_repository, &head_commit->object.oid,
+                                                      DEFAULT_ABBREV),
+                              repo_find_unique_abbrev(the_repository, &remoteheads->item->object.oid,
+                                                      DEFAULT_ABBREV));
                }
                commit = remoteheads->item;
                if (!commit) {
@@ -1610,7 +1620,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                         * Must first ensure that index matches HEAD before
                         * attempting a trivial merge.
                         */
-                       struct tree *head_tree = get_commit_tree(head_commit);
+                       struct tree *head_tree = repo_get_commit_tree(the_repository,
+                                                                     head_commit);
                        struct strbuf sb = STRBUF_INIT;
 
                        if (repo_index_has_changes(the_repository, head_tree,
@@ -1649,7 +1660,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                         * merge_bases again, otherwise "git merge HEAD^
                         * HEAD^^" would be missed.
                         */
-                       common_one = get_merge_bases(head_commit, j->item);
+                       common_one = repo_get_merge_bases(the_repository,
+                                                         head_commit,
+                                                         j->item);
                        if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
                                up_to_date = 0;
                                break;
index 5d22909122d195873f2427812084dc8bd4319180..d8e0b5afc079d2f71383eed6881b733fea251312 100644 (file)
@@ -1,8 +1,12 @@
 #include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
 #include "parse-options.h"
+#include "strbuf.h"
 #include "tag.h"
 #include "replace-object.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "fsck.h"
 #include "config.h"
 
@@ -14,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) {
@@ -51,7 +55,8 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
        void *buffer;
        const struct object_id *repl;
 
-       buffer = read_object_file(tagged_oid, &type, &size);
+       buffer = repo_read_object_file(the_repository, tagged_oid, &type,
+                                      &size);
        if (!buffer)
                die(_("could not read tagged object '%s'"),
                    oid_to_hex(tagged_oid));
@@ -80,7 +85,7 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
        int tagged_type;
        struct object_id result;
 
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             builtin_mktag_options,
                             builtin_mktag_usage, 0);
 
index 06d81400f558152292718a57c384e12078e2b9be..9a22d4e27735d55265fbf1a16cec8aeb66c27883 100644 (file)
@@ -4,10 +4,13 @@
  * Copyright (c) Junio C Hamano, 2006, 2009
  */
 #include "builtin.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 9a18a82b0575efdff2c98707179d827fd73eacb9..a72aebecaa2f3aa96f802b635b4d55c5f122d56c 100644 (file)
@@ -1,10 +1,13 @@
 #include "builtin.h"
-#include "cache.h"
+#include "abspath.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>]" \
@@ -79,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 edd7b931fdb95f84eec899acbf0b4ae2a120f2d7..05e7156034e04d637990cabf105f7fa967b0f2aa 100644 (file)
@@ -5,13 +5,22 @@
  */
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object-file.h"
 #include "pathspec.h"
 #include "lockfile.h"
 #include "dir.h"
 #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"
 #include "entry.h"
 
@@ -175,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;
@@ -295,7 +304,7 @@ 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) {
+                   && lstat(dst, &dest_st) == 0) {
                        bad = _("cannot move directory over file");
                        goto act_on_entry;
                }
index 97959bfaf9eb018dbe83780f60093e3f04f7be42..c706fa37201aeabc5bdc3eb752a5be859490a42d 100644 (file)
@@ -1,15 +1,20 @@
 #include "builtin.h"
-#include "cache.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "config.h"
 #include "commit.h"
 #include "tag.h"
 #include "refs.h"
+#include "object-name.h"
+#include "pager.h"
 #include "parse-options.h"
 #include "prio-queue.h"
 #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
@@ -181,7 +186,7 @@ static void name_rev(struct commit *start_commit,
        size_t parents_to_queue_nr, parents_to_queue_alloc = 0;
        struct rev_name *start_name;
 
-       parse_commit(start_commit);
+       repo_parse_commit(the_repository, start_commit);
        if (commit_is_before_cutoff(start_commit))
                return;
 
@@ -211,7 +216,7 @@ static void name_rev(struct commit *start_commit,
                        struct rev_name *parent_name;
                        int generation, distance;
 
-                       parse_commit(parent);
+                       repo_parse_commit(the_repository, parent);
                        if (commit_is_before_cutoff(parent))
                                continue;
 
@@ -493,7 +498,8 @@ static void show_name(const struct object *obj,
        else if (allow_undefined)
                printf("undefined\n");
        else if (always)
-               printf("%s\n", find_unique_abbrev(oid, DEFAULT_ABBREV));
+               printf("%s\n",
+                      repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
        else
                die("cannot describe '%s'", oid_to_hex(oid));
        strbuf_release(&buf);
@@ -527,7 +533,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
                        counter = 0;
 
                        *(p+1) = 0;
-                       if (!get_oid(p - (hexsz - 1), &oid)) {
+                       if (!repo_get_oid(the_repository, p - (hexsz - 1), &oid)) {
                                struct object *o =
                                        lookup_object(the_repository, &oid);
                                if (o)
@@ -567,7 +573,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                                   N_("ignore refs matching <pattern>")),
                OPT_GROUP(""),
                OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
-               OPT_BOOL(0, "stdin", &transform_stdin, N_("deprecated: use --annotate-stdin instead")),
+               OPT_BOOL_F(0,
+                          "stdin",
+                          &transform_stdin,
+                          N_("deprecated: use --annotate-stdin instead"),
+                          PARSE_OPT_HIDDEN),
                OPT_BOOL(0, "annotate-stdin", &annotate_stdin, N_("annotate text from stdin")),
                OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
                OPT_BOOL(0, "always",     &always,
@@ -604,7 +614,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                struct object *object;
                struct commit *commit;
 
-               if (get_oid(*argv, &oid)) {
+               if (repo_get_oid(the_repository, *argv, &oid)) {
                        fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
                                        *argv);
                        continue;
index 80d9dfd25cad2afcb90c0219894529bcc1558cac..9f38863dd507ff680cf8a006b81a413d75550b1b 100644 (file)
@@ -7,11 +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-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
 #include "blob.h"
 #include "pretty.h"
 #include "notes-merge.h"
 #include "notes-utils.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>"),
@@ -96,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)
@@ -110,11 +133,18 @@ 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,
-               const struct object_id *note_oid, char *note_path,
-               void *cb_data)
+                         const struct object_id *note_oid,
+                         char *note_path UNUSED,
+                         void *cb_data UNUSED)
 {
        printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid));
        return 0;
@@ -124,7 +154,7 @@ static void copy_obj_to_fd(int fd, const struct object_id *oid)
 {
        unsigned long size;
        enum object_type type;
-       char *buf = read_object_file(oid, &type, &size);
+       char *buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (buf) {
                if (size)
                        write_or_die(fd, buf, size);
@@ -151,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);
@@ -179,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);
@@ -193,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);
        }
 }
 
@@ -209,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');
-
-       if (get_oid(arg, &object))
+       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 = read_object_file(&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;
 }
 
@@ -280,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;
@@ -307,9 +385,9 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
                        die(_("malformed input line: '%s'."), buf.buf);
                strbuf_rtrim(split[0]);
                strbuf_rtrim(split[1]);
-               if (get_oid(split[0]->buf, &from_obj))
+               if (repo_get_oid(the_repository, split[0]->buf, &from_obj))
                        die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
-               if (get_oid(split[1]->buf, &to_obj))
+               if (repo_get_oid(the_repository, split[1]->buf, &to_obj))
                        die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
 
                if (rewrite_cmd)
@@ -377,7 +455,7 @@ static int list(int argc, const char **argv, const char *prefix)
 
        t = init_notes_check("list", 0);
        if (argc) {
-               if (get_oid(argv[0], &object))
+               if (repo_get_oid(the_repository, argv[0], &object))
                        die(_("failed to resolve '%s' as a valid ref."), argv[0]);
                note = get_note(t, &object);
                if (note) {
@@ -402,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,
@@ -419,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()
        };
 
@@ -430,9 +515,13 @@ 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 (get_oid(object_ref, &object))
+       if (repo_get_oid(the_repository, object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
 
        t = init_notes_check("add", NOTES_INIT_WRITABLE);
@@ -520,12 +609,12 @@ static int copy(int argc, const char **argv, const char *prefix)
                usage_with_options(git_notes_copy_usage, options);
        }
 
-       if (get_oid(argv[0], &from_obj))
+       if (repo_get_oid(the_repository, argv[0], &from_obj))
                die(_("failed to resolve '%s' as a valid ref."), argv[0]);
 
        object_ref = 1 < argc ? argv[1] : "HEAD";
 
-       if (get_oid(object_ref, &object))
+       if (repo_get_oid(the_repository, object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
 
        t = init_notes_check("copy", NOTES_INIT_WRITABLE);
@@ -568,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,
@@ -584,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");
@@ -597,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"
@@ -604,7 +703,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
 
        object_ref = 1 < argc ? argv[1] : "HEAD";
 
-       if (get_oid(object_ref, &object))
+       if (repo_get_oid(the_repository, object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
 
        t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
@@ -616,14 +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 = read_object_file(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) {
@@ -666,7 +768,7 @@ static int show(int argc, const char **argv, const char *prefix)
 
        object_ref = argc ? argv[0] : "HEAD";
 
-       if (get_oid(object_ref, &object))
+       if (repo_get_oid(the_repository, object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
 
        t = init_notes_check("show", 0);
@@ -716,11 +818,11 @@ static int merge_commit(struct notes_merge_options *o)
         * and target notes ref from .git/NOTES_MERGE_REF.
         */
 
-       if (get_oid("NOTES_MERGE_PARTIAL", &oid))
+       if (repo_get_oid(the_repository, "NOTES_MERGE_PARTIAL", &oid))
                die(_("failed to read ref NOTES_MERGE_PARTIAL"));
        else if (!(partial = lookup_commit_reference(the_repository, &oid)))
                die(_("could not find commit from NOTES_MERGE_PARTIAL."));
-       else if (parse_commit(partial))
+       else if (repo_parse_commit(the_repository, partial))
                die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
 
        if (partial->parents)
@@ -741,7 +843,8 @@ static int merge_commit(struct notes_merge_options *o)
 
        /* Reuse existing commit message in reflog message */
        memset(&pretty_ctx, 0, sizeof(pretty_ctx));
-       format_commit_message(partial, "%s", &msg, &pretty_ctx);
+       repo_format_commit_message(the_repository, partial, "%s", &msg,
+                                  &pretty_ctx);
        strbuf_trim(&msg);
        strbuf_insertstr(&msg, 0, "notes: ");
        update_ref(msg.buf, o->local_ref, &oid,
@@ -895,7 +998,7 @@ static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag
 {
        int status;
        struct object_id oid;
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                return error(_("Failed to resolve '%s' as a valid ref."), name);
        status = remove_note(t, oid.hash);
        if (status)
index 74a167a180cd4080919d8c3a614c098ad96a2b42..d2a162d52804cf7fdf1fd1a11303f2380c24c9e3 100644 (file)
@@ -1,5 +1,7 @@
 #include "builtin.h"
-#include "cache.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "config.h"
 #include "attr.h"
 #include "strvec.h"
 #include "list.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
 #include "dir.h"
 #include "midx.h"
 #include "trace2.h"
 #include "shallow.h"
 #include "promisor-remote.h"
 #include "pack-mtimes.h"
+#include "parse-options.h"
 
 /*
  * Objects we are going to pack are collected in the `to_pack` structure.
@@ -288,11 +293,13 @@ static void *get_delta(struct object_entry *entry)
        void *buf, *base_buf, *delta_buf;
        enum object_type type;
 
-       buf = read_object_file(&entry->idx.oid, &type, &size);
+       buf = repo_read_object_file(the_repository, &entry->idx.oid, &type,
+                                   &size);
        if (!buf)
                die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
-       base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
-                                   &base_size);
+       base_buf = repo_read_object_file(the_repository,
+                                        &DELTA(entry)->idx.oid, &type,
+                                        &base_size);
        if (!base_buf)
                die("unable to read %s",
                    oid_to_hex(&DELTA(entry)->idx.oid));
@@ -454,7 +461,9 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
                                       &size, NULL)) != NULL)
                        buf = NULL;
                else {
-                       buf = read_object_file(&entry->idx.oid, &type, &size);
+                       buf = repo_read_object_file(the_repository,
+                                                   &entry->idx.oid, &type,
+                                                   &size);
                        if (!buf)
                                die(_("unable to read %s"),
                                    oid_to_hex(&entry->idx.oid));
@@ -1320,7 +1329,7 @@ static int no_try_delta(const char *path)
 
        if (!check)
                check = attr_check_initl("delta", NULL);
-       git_check_attr(the_repository->index, NULL, path, check);
+       git_check_attr(the_repository->index, path, check);
        if (ATTR_FALSE(check->items[0].value))
                return 1;
        return 0;
@@ -1590,7 +1599,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
 
 static int add_object_entry_from_bitmap(const struct object_id *oid,
                                        enum object_type type,
-                                       int flags, uint32_t name_hash,
+                                       int flags UNUSED, uint32_t name_hash,
                                        struct packed_git *pack, off_t offset)
 {
        display_progress(progress_state, ++nr_seen);
@@ -1665,7 +1674,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
        /* Did not find one.  Either we got a bogus request or
         * we need to read and perhaps cache.
         */
-       data = read_object_file(oid, &type, &size);
+       data = repo_read_object_file(the_repository, oid, &type, &size);
        if (!data)
                return NULL;
        if (type != OBJ_TREE) {
@@ -2074,7 +2083,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
 
        if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
                                     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
-               if (has_promisor_remote()) {
+               if (repo_has_promisor_remote(the_repository)) {
                        prefetch_to_pack(object_index);
                        if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
                                                     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
@@ -2525,7 +2534,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
        /* Load data if not already done */
        if (!trg->data) {
                packing_data_lock(&to_pack);
-               trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
+               trg->data = repo_read_object_file(the_repository,
+                                                 &trg_entry->idx.oid, &type,
+                                                 &sz);
                packing_data_unlock(&to_pack);
                if (!trg->data)
                        die(_("object %s cannot be read"),
@@ -2538,7 +2549,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
        }
        if (!src->data) {
                packing_data_lock(&to_pack);
-               src->data = read_object_file(&src_entry->idx.oid, &type, &sz);
+               src->data = repo_read_object_file(the_repository,
+                                                 &src_entry->idx.oid, &type,
+                                                 &sz);
                packing_data_unlock(&to_pack);
                if (!src->data) {
                        if (src_entry->preferred_base) {
@@ -3120,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")) {
@@ -3165,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);
@@ -3176,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);
@@ -3212,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. */
@@ -3260,13 +3274,14 @@ static int add_object_entry_from_pack(const struct object_id *oid,
        return 0;
 }
 
-static void show_commit_pack_hint(struct commit *commit, void *_data)
+static void show_commit_pack_hint(struct commit *commit UNUSED,
+                                 void *data UNUSED)
 {
        /* nothing to do; commits don't have a namehash */
 }
 
 static void show_object_pack_hint(struct object *object, const char *name,
-                                 void *_data)
+                                 void *data UNUSED)
 {
        struct object_entry *oe = packlist_find(&to_pack, &object->oid);
        if (!oe)
@@ -3344,16 +3359,16 @@ static void read_packs_list_from_stdin(void)
        }
 
        string_list_sort(&include_packs);
+       string_list_remove_duplicates(&include_packs, 0);
        string_list_sort(&exclude_packs);
+       string_list_remove_duplicates(&exclude_packs, 0);
 
        for (p = get_all_packs(the_repository); p; p = p->next) {
                const char *pack_name = pack_basename(p);
 
-               item = string_list_lookup(&include_packs, pack_name);
-               if (!item)
-                       item = string_list_lookup(&exclude_packs, pack_name);
-
-               if (item)
+               if ((item = string_list_lookup(&include_packs, pack_name)))
+                       item->util = p;
+               if ((item = string_list_lookup(&exclude_packs, pack_name)))
                        item->util = p;
        }
 
@@ -3464,7 +3479,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
        return;
 }
 
-static void show_cruft_object(struct object *obj, const char *name, void *data)
+static void show_cruft_object(struct object *obj, const char *name, void *data UNUSED)
 {
        /*
         * if we did not record it earlier, it's at least as old as our
@@ -3484,7 +3499,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
        show_cruft_object((struct object*)commit, NULL, data);
 }
 
-static int cruft_include_check_obj(struct object *obj, void *data)
+static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
 {
        return !has_object_kept_pack(&obj->oid, IN_CORE_KEEP_PACKS);
 }
@@ -3663,7 +3678,7 @@ static void read_object_list_from_stdin(void)
        }
 }
 
-static void show_commit(struct commit *commit, void *data)
+static void show_commit(struct commit *commit, void *data UNUSED)
 {
        add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
 
@@ -3674,7 +3689,8 @@ static void show_commit(struct commit *commit, void *data)
                propagate_island_marks(commit);
 }
 
-static void show_object(struct object *obj, const char *name, void *data)
+static void show_object(struct object *obj, const char *name,
+                       void *data UNUSED)
 {
        add_preferred_base_object(name);
        add_object_entry(&obj->oid, obj->type, name, 0);
@@ -3761,7 +3777,7 @@ static void show_edge(struct commit *commit)
 static int add_object_in_unpacked_pack(const struct object_id *oid,
                                       struct packed_git *pack,
                                       uint32_t pos,
-                                      void *_data)
+                                      void *data UNUSED)
 {
        if (cruft) {
                off_t offset;
@@ -3795,7 +3811,7 @@ static void add_objects_in_unpacked_packs(void)
 }
 
 static int add_loose_object(const struct object_id *oid, const char *path,
-                           void *data)
+                           void *data UNUSED)
 {
        enum object_type type = oid_object_info(the_repository, oid, NULL);
 
@@ -3946,13 +3962,13 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
 }
 
 static void record_recent_object(struct object *obj,
-                                const char *name,
-                                void *data)
+                                const char *name UNUSED,
+                                void *data UNUSED)
 {
        oid_array_append(&recent_objects, &obj->oid);
 }
 
-static void record_recent_commit(struct commit *commit, void *data)
+static void record_recent_commit(struct commit *commit, void *data UNUSED)
 {
        oid_array_append(&recent_objects, &commit->object.oid);
 }
@@ -4101,6 +4117,18 @@ 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)
+{
+       BUG_ON_OPT_ARG(arg);
+
+       if (!unset)
+               progress = 0;
+       else if (!progress)
+               progress = 1;
+       return 0;
+}
+
 static int option_parse_index_version(const struct option *opt,
                                      const char *arg, int unset)
 {
@@ -4162,8 +4190,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", NULL, 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,
@@ -4239,8 +4268,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,
@@ -4267,7 +4296,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) {
@@ -4277,9 +4306,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        }
 
        reset_pack_idx_option(&pack_idx_opts);
+       pack_idx_opts.flags |= WRITE_REV;
        git_config(git_pack_config, NULL);
-       if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
-               pack_idx_opts.flags |= WRITE_REV;
+       if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+               pack_idx_opts.flags &= ~WRITE_REV;
 
        progress = isatty(2);
        argc = parse_options(argc, argv, prefix, pack_objects_options,
index ecd49ca268f53bb4b986d5fdbf3876c0dc010733..4c735ba069caf6626791d85741f78c3869a5c89d 100644 (file)
@@ -7,9 +7,11 @@
 */
 
 #include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 #define BLKSIZE 512
 
@@ -557,7 +559,7 @@ static void load_all(void)
        }
 }
 
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
 {
        int i;
        int i_still_use_this = 0;
@@ -603,6 +605,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
                        "option, '--i-still-use-this', on the command line\n"
                        "and let us know you still use it by sending an e-mail\n"
                        "to <git@vger.kernel.org>.  Thanks.\n"), stderr);
+               die(_("refusing to run without --i-still-use-this"));
        }
 
        if (load_all_packs)
index 27c2ca06acb7d68571e6e4547a7670f62eef2619..bcf383cac9dd875354d3c91152f7b8d635f82ff4 100644 (file)
@@ -1,24 +1,48 @@
 #include "builtin.h"
 #include "config.h"
+#include "gettext.h"
 #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 f840fbf1c7e81332bd5f898b6eca7363c645ec60..3894d2b970612cab4a47250dd53da5b0908c820e 100644 (file)
@@ -1,7 +1,9 @@
-#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"
 
 static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
@@ -194,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;
 
@@ -207,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 da3273a268b47d89be86ac05780905fa9ad766d8..ca3578e158840148aea2b074a3d44fdc64332b58 100644 (file)
@@ -1,4 +1,5 @@
 #include "builtin.h"
+#include "gettext.h"
 #include "parse-options.h"
 #include "prune-packed.h"
 
index 27192201086877115157d6f5cedb2f8fc1e231a6..57fe31467fe5ac9768f1b04f7c7e6dd3e9409468 100644 (file)
@@ -1,13 +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 "object-store.h"
+#include "replace-object.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "shallow.h"
 
 static const char * const prune_usage[] = {
@@ -98,7 +105,8 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
        return 0;
 }
 
-static int prune_cruft(const char *basename, const char *path, void *data)
+static int prune_cruft(const char *basename, const char *path,
+                      void *data UNUSED)
 {
        if (starts_with(basename, "tmp_obj_"))
                prune_tmp_file(path);
@@ -107,7 +115,8 @@ static int prune_cruft(const char *basename, const char *path, void *data)
        return 0;
 }
 
-static int prune_subdir(unsigned int nr, const char *path, void *data)
+static int prune_subdir(unsigned int nr UNUSED, const char *path,
+                       void *data UNUSED)
 {
        if (!show_only)
                rmdir(path);
@@ -156,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);
@@ -168,7 +177,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
                struct object_id oid;
                const char *name = *argv++;
 
-               if (!get_oid(name, &oid)) {
+               if (!repo_get_oid(the_repository, name, &oid)) {
                        struct object *object = parse_object_or_die(&oid,
                                                                    name);
                        add_pending_object(&revs, object, "");
index 1ab4de0005da3f6d2aa4b6a93d61544818af8700..be2b2c9ebc97b2a1620b93e1766e0ccfa6c7843a 100644 (file)
@@ -6,15 +6,21 @@
  * Fetch one or more remote refs and merge it/them into the current HEAD.
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "merge.h"
+#include "object-name.h"
 #include "parse-options.h"
 #include "exec-cmd.h"
 #include "run-command.h"
 #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"
@@ -357,10 +363,9 @@ 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)
 {
-       int status;
-
        if (!strcmp(var, "rebase.autostash")) {
                config_autostash = git_config_bool(var, value);
                return 0;
@@ -372,11 +377,7 @@ static int git_pull_config(const char *var, const char *value, void *cb)
                check_trust_level = 0;
        }
 
-       status = git_gpg_config(var, value, cb);
-       if (status)
-               return status;
-
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 /**
@@ -1036,7 +1037,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        if (file_exists(git_path_merge_head(the_repository)))
                die_conclude_merge();
 
-       if (get_oid("HEAD", &orig_head))
+       if (repo_get_oid(the_repository, "HEAD", &orig_head))
                oidclr(&orig_head);
 
        if (opt_rebase) {
@@ -1049,7 +1050,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                if (!opt_autostash)
                        require_clean_work_tree(the_repository,
                                N_("pull with rebase"),
-                               _("please commit or stash them."), 1, 0);
+                               _("Please commit or stash them."), 1, 0);
 
                if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
                        oidclr(&rebase_fork_point);
@@ -1061,7 +1062,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        if (opt_dry_run)
                return 0;
 
-       if (get_oid("HEAD", &curr_head))
+       if (repo_get_oid(the_repository, "HEAD", &curr_head))
                oidclr(&curr_head);
 
        if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
index 8f7d326ab3f4b06d3d3d1262d5276fd8c6b2b968..2e708383c24ba86e07fc14b0139afb28d489c014 100644 (file)
@@ -1,19 +1,24 @@
 /*
  * "git push"
  */
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
 #include "branch.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
 #include "refs.h"
 #include "refspec.h"
 #include "run-command.h"
-#include "builtin.h"
 #include "remote.h"
 #include "transport.h"
 #include "parse-options.h"
+#include "pkt-line.h"
+#include "repository.h"
 #include "submodule.h"
 #include "submodule-config.h"
 #include "send-pack.h"
+#include "trace2.h"
 #include "color.h"
 
 static const char * const push_usage[] = {
@@ -296,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[] =
@@ -322,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)
 {
@@ -504,15 +509,11 @@ 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;
-       int status;
-
-       status = git_gpg_config(k, v, NULL);
-       if (status)
-               return status;
 
        if (!strcmp(k, "push.followtags")) {
                if (git_config_bool(k, v))
@@ -576,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)
@@ -594,11 +595,12 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT__VERBOSITY(&verbosity),
                OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
-               OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+               OPT_BIT( 0 , "all", &flags, N_("push all branches"), TRANSPORT_PUSH_ALL),
+               OPT_ALIAS( 0 , "branches", "all"),
                OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
                OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")),
-               OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+               OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --branches or --mirror)")),
                OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
                OPT_BIT( 0,  "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
                OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
@@ -625,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()
        };
 
@@ -641,7 +640,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        set_push_cert_flags(&flags, push_cert);
 
        if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
-               die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--mirror/--tags");
+               die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--branches/--mirror/--tags");
        if (deleterefs && argc < 2)
                die(_("--delete doesn't make sense without any refs"));
 
index aecfae12d3ae0777a57bec2c02dffa7cffde3d8f..e455a4795cc8101576a806ee68df71a56c7661ce 100644 (file)
@@ -1,8 +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[] = {
@@ -65,20 +67,20 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
 
        if (dash_dash == 3 ||
            (dash_dash < 0 && argc > 2 &&
-            !get_oid_committish(argv[0], &oid) &&
-            !get_oid_committish(argv[1], &oid) &&
-            !get_oid_committish(argv[2], &oid))) {
+            !repo_get_oid_committish(the_repository, argv[0], &oid) &&
+            !repo_get_oid_committish(the_repository, argv[1], &oid) &&
+            !repo_get_oid_committish(the_repository, argv[2], &oid))) {
                if (dash_dash < 0)
                        ; /* already validated arguments */
-               else if (get_oid_committish(argv[0], &oid))
+               else if (repo_get_oid_committish(the_repository, argv[0], &oid))
                        usage_msg_optf(_("not a revision: '%s'"),
                                       builtin_range_diff_usage, options,
                                       argv[0]);
-               else if (get_oid_committish(argv[1], &oid))
+               else if (repo_get_oid_committish(the_repository, argv[1], &oid))
                        usage_msg_optf(_("not a revision: '%s'"),
                                       builtin_range_diff_usage, options,
                                       argv[1]);
-               else if (get_oid_committish(argv[2], &oid))
+               else if (repo_get_oid_committish(the_repository, argv[2], &oid))
                        usage_msg_optf(_("not a revision: '%s'"),
                                       builtin_range_diff_usage, options,
                                       argv[2]);
index 3ce75417833bf9f57ca1ddfa17a53c67ef39a9d8..1fec702a04fa9b9785d767c4e8b44e50d0e3a89c 100644 (file)
@@ -5,18 +5,23 @@
  */
 
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "object.h"
+#include "object-name.h"
 #include "tree.h"
 #include "tree-walk.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"
 
@@ -87,9 +92,9 @@ static int debug_merge(const struct cache_entry * const *stages,
 {
        int i;
 
-       printf("* %d-way merge\n", o->merge_size);
+       printf("* %d-way merge\n", o->internal.merge_size);
        debug_stage("index", stages[0], o);
-       for (i = 1; i <= o->merge_size; i++) {
+       for (i = 1; i <= o->internal.merge_size; i++) {
                char buf[24];
                xsnprintf(buf, sizeof(buf), "ent#%d", i);
                debug_stage(buf, stages[i], o);
@@ -97,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)
@@ -144,7 +150,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
                OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
                OPT_BOOL(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
                         N_("skip applying sparse checkout filter")),
-               OPT_BOOL(0, "debug-unpack", &opts.debug_unpack,
+               OPT_BOOL(0, "debug-unpack", &opts.internal.debug_unpack,
                         N_("debug unpack-trees")),
                OPT_CALLBACK_F(0, "recurse-submodules", NULL,
                            "checkout", "control recursive updating of submodules",
@@ -198,7 +204,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
 
-               if (get_oid(arg, &oid))
+               if (repo_get_oid(the_repository, arg, &oid))
                        die("Not a valid object name %s", arg);
                if (list_tree(&oid) < 0)
                        die("failed to unpack tree object %s", arg);
@@ -247,7 +253,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
                        opts.head_idx = 1;
        }
 
-       if (opts.debug_unpack)
+       if (opts.internal.debug_unpack)
                opts.fn = debug_merge;
 
        /* If we're going to prime_cache_tree later, skip cache tree update */
@@ -263,7 +269,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
        if (unpack_trees(nr_trees, t, &opts))
                return 128;
 
-       if (opts.debug_unpack || opts.dry_run)
+       if (opts.internal.debug_unpack || opts.dry_run)
                return 0; /* do not write the index out */
 
        /*
index 6635f10d5294d16d017eae225de799efb7b1b9aa..50cb85751f798e81d30d631754a3aaad443c3c49 100644 (file)
@@ -6,6 +6,10 @@
 
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "run-command.h"
 #include "exec-cmd.h"
 #include "strvec.h"
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "lockfile.h"
+#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"
@@ -28,6 +35,7 @@
 #include "sequencer.h"
 #include "rebase-interactive.h"
 #include "reset.h"
+#include "trace2.h"
 #include "hook.h"
 
 static char const * const builtin_rebase_usage[] = {
@@ -116,13 +124,15 @@ struct rebase_options {
        struct string_list exec;
        int allow_empty_message;
        int rebase_merges, rebase_cousins;
-       char *strategy, *strategy_opts;
+       char *strategy;
+       struct string_list strategy_opts;
        struct strbuf git_format_patch_opt;
        int reschedule_failed_exec;
        int reapply_cherry_picks;
        int fork_point;
        int update_refs;
        int config_autosquash;
+       int config_rebase_merges;
        int config_update_refs;
 };
 
@@ -140,8 +150,11 @@ struct rebase_options {
                .allow_empty_message = 1,               \
                .autosquash = -1,                       \
                .config_autosquash = -1,                \
+               .rebase_merges = -1,                    \
+               .config_rebase_merges = -1,             \
                .update_refs = -1,                      \
                .config_update_refs = -1,               \
+               .strategy_opts = STRING_LIST_INIT_NODUP,\
        }
 
 static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -175,8 +188,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
                replay.default_strategy = NULL;
        }
 
-       if (opts->strategy_opts)
-               parse_strategy_opts(&replay, opts->strategy_opts);
+       for (size_t i = 0; i < opts->strategy_opts.nr; i++)
+               strvec_push(&replay.xopts, opts->strategy_opts.items[i].string);
 
        if (opts->squash_onto) {
                oidcpy(&replay.squash_onto, opts->squash_onto);
@@ -196,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)))
@@ -218,13 +231,15 @@ static int get_revision_ranges(struct commit *upstream, struct commit *onto,
        *revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
                             oid_to_hex(orig_head));
 
-       shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
+       shorthead = repo_find_unique_abbrev(the_repository, orig_head,
+                                           DEFAULT_ABBREV);
 
        if (upstream) {
                const char *shortrev;
 
-               shortrev = find_unique_abbrev(&base_rev->object.oid,
-                                             DEFAULT_ABBREV);
+               shortrev = repo_find_unique_abbrev(the_repository,
+                                                  &base_rev->object.oid,
+                                                  DEFAULT_ABBREV);
 
                *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead);
        } else
@@ -482,24 +497,6 @@ static int read_basic_state(struct rebase_options *opts)
                opts->gpg_sign_opt = xstrdup(buf.buf);
        }
 
-       if (file_exists(state_dir_path("strategy", opts))) {
-               strbuf_reset(&buf);
-               if (!read_oneliner(&buf, state_dir_path("strategy", opts),
-                                  READ_ONELINER_WARN_MISSING))
-                       return -1;
-               free(opts->strategy);
-               opts->strategy = xstrdup(buf.buf);
-       }
-
-       if (file_exists(state_dir_path("strategy_opts", opts))) {
-               strbuf_reset(&buf);
-               if (!read_oneliner(&buf, state_dir_path("strategy_opts", opts),
-                                  READ_ONELINER_WARN_MISSING))
-                       return -1;
-               free(opts->strategy_opts);
-               opts->strategy_opts = xstrdup(buf.buf);
-       }
-
        strbuf_release(&buf);
 
        return 0;
@@ -517,12 +514,6 @@ static int rebase_write_basic_state(struct rebase_options *opts)
                write_file(state_dir_path("quiet", opts), "%s", "");
        if (opts->flags & REBASE_VERBOSE)
                write_file(state_dir_path("verbose", opts), "%s", "");
-       if (opts->strategy)
-               write_file(state_dir_path("strategy", opts), "%s",
-                          opts->strategy);
-       if (opts->strategy_opts)
-               write_file(state_dir_path("strategy_opts", opts), "%s",
-                          opts->strategy_opts);
        if (opts->allow_rerere_autoupdate > 0)
                write_file(state_dir_path("allow_rerere_autoupdate", opts),
                           "-%s-rerere-autoupdate",
@@ -660,7 +651,7 @@ static int run_am(struct rebase_options *opts)
        format_patch.git_cmd = 1;
        strvec_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
                     "--full-index", "--cherry-pick", "--right-only",
-                    "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
+                    "--default-prefix", "--no-renames",
                     "--no-cover-letter", "--pretty=mboxrd", "--topo-order",
                     "--no-base", NULL);
        if (opts->git_format_patch_opt.len)
@@ -771,7 +762,18 @@ static int run_specific_rebase(struct rebase_options *opts)
        return status ? -1 : 0;
 }
 
-static int rebase_config(const char *var, const char *value, void *data)
+static void parse_rebase_merges_value(struct rebase_options *options, const char *value)
+{
+       if (!strcmp("no-rebase-cousins", value))
+               options->rebase_cousins = 0;
+       else if (!strcmp("rebase-cousins", value))
+               options->rebase_cousins = 1;
+       else
+               die(_("Unknown rebase-merges mode: %s"), value);
+}
+
+static int rebase_config(const char *var, const char *value,
+                        const struct config_context *ctx, void *data)
 {
        struct rebase_options *opts = data;
 
@@ -800,6 +802,17 @@ static int rebase_config(const char *var, const char *value, void *data)
                return 0;
        }
 
+       if (!strcmp(var, "rebase.rebasemerges")) {
+               opts->config_rebase_merges = git_parse_maybe_bool(value);
+               if (opts->config_rebase_merges < 0) {
+                       opts->config_rebase_merges = 1;
+                       parse_rebase_merges_value(opts, value);
+               } else {
+                       opts->rebase_cousins = 0;
+               }
+               return 0;
+       }
+
        if (!strcmp(var, "rebase.updaterefs")) {
                opts->config_update_refs = git_config_bool(var, value);
                return 0;
@@ -819,7 +832,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)
@@ -851,7 +864,7 @@ static int checkout_up_to_date(struct rebase_options *options)
 static int is_linear_history(struct commit *from, struct commit *to)
 {
        while (to && to != from) {
-               parse_commit(to);
+               repo_parse_commit(the_repository, to);
                if (!to->parents)
                        return 1;
                if (to->parents->next)
@@ -880,7 +893,7 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
        if (!upstream)
                goto done;
 
-       merge_bases = get_merge_bases(upstream, head);
+       merge_bases = repo_get_merge_bases(the_repository, upstream, head);
        if (!merge_bases || merge_bases->next)
                goto done;
 
@@ -899,7 +912,8 @@ static void fill_branch_base(struct rebase_options *options,
 {
        struct commit_list *merge_bases = NULL;
 
-       merge_bases = get_merge_bases(options->onto, options->orig_head);
+       merge_bases = repo_get_merge_bases(the_repository, options->onto,
+                                          options->orig_head);
        if (!merge_bases || merge_bases->next)
                oidcpy(branch_base, null_oid());
        else
@@ -980,6 +994,28 @@ static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
+static int parse_opt_rebase_merges(const struct option *opt, const char *arg, int unset)
+{
+       struct rebase_options *options = opt->value;
+
+       options->rebase_merges = !unset;
+       options->rebase_cousins = 0;
+
+       if (arg) {
+               if (!*arg) {
+                       warning(_("--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."));
+                       return 0;
+               }
+               parse_rebase_merges_value(options, arg);
+       }
+
+       return 0;
+}
+
 static void NORETURN error_on_missing_default_upstream(void)
 {
        struct branch *current_branch = branch_get(NULL);
@@ -1035,8 +1071,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        struct object_id branch_base;
        int ignore_whitespace = 0;
        const char *gpg_sign = NULL;
-       const char *rebase_merges = NULL;
-       struct string_list strategy_options = STRING_LIST_INIT_NODUP;
        struct object_id squash_onto;
        char *squash_onto_name = NULL;
        char *keep_base_onto_name = NULL;
@@ -1137,15 +1171,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                           &options.allow_empty_message,
                           N_("allow rebasing commits with empty messages"),
                           PARSE_OPT_HIDDEN),
-               {OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
-                       N_("mode"),
+               OPT_CALLBACK_F('r', "rebase-merges", &options, N_("mode"),
                        N_("try to rebase merges instead of skipping them"),
-                       PARSE_OPT_OPTARG, NULL, (intptr_t)""},
+                       PARSE_OPT_OPTARG, parse_opt_rebase_merges),
                OPT_BOOL(0, "fork-point", &options.fork_point,
                         N_("use 'merge-base --fork-point' to refine upstream")),
                OPT_STRING('s', "strategy", &options.strategy,
                           N_("strategy"), N_("use the given merge strategy")),
-               OPT_STRING_LIST('X', "strategy-option", &strategy_options,
+               OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
                                N_("option"),
                                N_("pass the argument through to the merge "
                                   "strategy")),
@@ -1261,7 +1294,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                int fd;
 
                /* Sanity check */
-               if (get_oid("HEAD", &head))
+               if (repo_get_oid(the_repository, "HEAD", &head))
                        die(_("Cannot read HEAD"));
 
                fd = repo_hold_locked_index(the_repository, &lock_file, 0);
@@ -1436,17 +1469,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        if (options.exec.nr)
                imply_merge(&options, "--exec");
 
-       if (rebase_merges) {
-               if (!*rebase_merges)
-                       ; /* default mode; do nothing */
-               else if (!strcmp("rebase-cousins", rebase_merges))
-                       options.rebase_cousins = 1;
-               else if (strcmp("no-rebase-cousins", rebase_merges))
-                       die(_("Unknown mode: %s"), rebase_merges);
-               options.rebase_merges = 1;
-               imply_merge(&options, "--rebase-merges");
-       }
-
        if (options.type == REBASE_APPLY) {
                if (ignore_whitespace)
                        strvec_push(&options.git_am_opts,
@@ -1459,23 +1481,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        } else {
                /* REBASE_MERGE */
                if (ignore_whitespace) {
-                       string_list_append(&strategy_options,
+                       string_list_append(&options.strategy_opts,
                                           "ignore-space-change");
                }
        }
 
-       if (strategy_options.nr) {
-               int i;
-
-               if (!options.strategy)
-                       options.strategy = "ort";
-
-               strbuf_reset(&buf);
-               for (i = 0; i < strategy_options.nr; i++)
-                       strbuf_addf(&buf, " --%s",
-                                   strategy_options.items[i].string);
-               options.strategy_opts = xstrdup(buf.buf);
-       }
+       if (options.strategy_opts.nr && !options.strategy)
+               options.strategy = "ort";
 
        if (options.strategy) {
                options.strategy = xstrdup(options.strategy);
@@ -1513,7 +1525,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                                die(_("apply options and merge options "
                                          "cannot be used together"));
                        else if (options.autosquash == -1 && options.config_autosquash == 1)
-                               die(_("apply options are incompatible with rebase.autosquash.  Consider adding --no-autosquash"));
+                               die(_("apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash"));
+                       else if (options.rebase_merges == -1 && options.config_rebase_merges == 1)
+                               die(_("apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges"));
                        else if (options.update_refs == -1 && options.config_update_refs == 1)
                                die(_("apply options are incompatible with rebase.updateRefs.  Consider adding --no-update-refs"));
                        else
@@ -1526,6 +1540,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        options.update_refs = (options.update_refs >= 0) ? options.update_refs :
                             ((options.config_update_refs >= 0) ? options.config_update_refs : 0);
 
+       if (options.rebase_merges == 1)
+               imply_merge(&options, "--rebase-merges");
+       options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
+                               ((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
+
        if (options.autosquash == 1)
                imply_merge(&options, "--autosquash");
        options.autosquash = (options.autosquash >= 0) ? options.autosquash :
@@ -1680,7 +1699,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        } else if (!options.onto_name)
                options.onto_name = options.upstream_name;
        if (strstr(options.onto_name, "...")) {
-               if (get_oid_mb(options.onto_name, &branch_base) < 0) {
+               if (repo_get_oid_mb(the_repository, options.onto_name, &branch_base) < 0) {
                        if (keep_base)
                                die(_("'%s': need exactly one merge base with branch"),
                                    options.upstream_name);
@@ -1783,7 +1802,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                }
 
                /* We want color (if set), but no pager */
-               diff_setup(&opts);
+               repo_diff_setup(the_repository, &opts);
                opts.stat_width = -1; /* use full terminal width */
                opts.stat_graph_width = -1; /* respect statGraphWidth config */
                opts.output_format |=
@@ -1850,10 +1869,9 @@ cleanup:
        free(options.gpg_sign_opt);
        string_list_clear(&options.exec, 0);
        free(options.strategy);
-       free(options.strategy_opts);
+       string_list_clear(&options.strategy_opts, 0);
        strbuf_release(&options.git_format_patch_opt);
        free(squash_onto_name);
        free(keep_base_onto_name);
-       string_list_clear(&strategy_options, 0);
        return !!ret;
 }
index cd5c7a28eff08f048b79a9d739800709c443c160..8c4f0cb90a936b2b24b8b7b9e8b1b789c33bff51 100644 (file)
@@ -1,6 +1,10 @@
 #include "builtin.h"
+#include "abspath.h"
 #include "repository.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "pack.h"
 #include "refs.h"
 #include "tmp-objdir.h"
 #include "oidset.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "protocol.h"
 #include "commit-reach.h"
+#include "server-info.h"
+#include "trace.h"
+#include "trace2.h"
 #include "worktree.h"
 #include "shallow.h"
+#include "parse-options.h"
 
 static const char * const receive_pack_usage[] = {
        N_("git receive-pack <git-dir>"),
@@ -80,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";
@@ -129,14 +139,11 @@ 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);
 
-       if (status)
-               return status;
-
-       status = git_gpg_config(var, value, NULL);
        if (status)
                return status;
 
@@ -151,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;
        }
 
@@ -224,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;
        }
 
@@ -239,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;
        }
 
@@ -260,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)
@@ -331,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)
@@ -1347,7 +1356,7 @@ static int head_has_history(void)
 {
        struct object_id oid;
 
-       return !get_oid("HEAD", &oid);
+       return !repo_get_oid(the_repository, "HEAD", &oid);
 }
 
 static const char *push_to_deploy(unsigned char *sha1,
@@ -1463,8 +1472,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                find_shared_symref(worktrees, "HEAD", name);
 
        /* only refs/... are allowed */
-       if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
-               rp_error("refusing to create funny ref '%s' remotely", name);
+       if (!starts_with(name, "refs/") ||
+           check_refname_format(name + 5, is_null_oid(new_oid) ?
+                                REFNAME_ALLOW_ONELEVEL : 0)) {
+               rp_error("refusing to update funny ref '%s' remotely", name);
                ret = "funny refname";
                goto out;
        }
@@ -1494,7 +1505,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
        }
 
-       if (!is_null_oid(new_oid) && !has_object_file(new_oid)) {
+       if (!is_null_oid(new_oid) && !repo_has_object_file(the_repository, new_oid)) {
                error("unpack should have generated %s, "
                      "but I can't find it!", oid_to_hex(new_oid));
                ret = "bad pack";
@@ -1548,7 +1559,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
                old_commit = (struct commit *)old_object;
                new_commit = (struct commit *)new_object;
-               if (!in_merge_bases(old_commit, new_commit)) {
+               if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
                        rp_error("denying non-fast-forward %s"
                                 " (you should pull first)", name);
                        ret = "non-fast-forward";
@@ -1681,11 +1692,11 @@ static void check_aliased_update_internal(struct command *cmd,
        rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
                 " its target '%s' (%s..%s)",
                 cmd->ref_name,
-                find_unique_abbrev(&cmd->old_oid, DEFAULT_ABBREV),
-                find_unique_abbrev(&cmd->new_oid, DEFAULT_ABBREV),
+                repo_find_unique_abbrev(the_repository, &cmd->old_oid, DEFAULT_ABBREV),
+                repo_find_unique_abbrev(the_repository, &cmd->new_oid, DEFAULT_ABBREV),
                 dst_cmd->ref_name,
-                find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV),
-                find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV));
+                repo_find_unique_abbrev(the_repository, &dst_cmd->old_oid, DEFAULT_ABBREV),
+                repo_find_unique_abbrev(the_repository, &dst_cmd->new_oid, DEFAULT_ABBREV));
 
        cmd->error_string = dst_cmd->error_string =
                "inconsistent aliased update";
@@ -2089,7 +2100,7 @@ static struct command *read_head_info(struct packet_reader *reader,
                        const char *feature_list = reader->line + linelen + 1;
                        const char *hash = NULL;
                        const char *client_sid;
-                       int len = 0;
+                       size_t len = 0;
                        if (parse_feature_request(feature_list, "report-status"))
                                report_status = 1;
                        if (parse_feature_request(feature_list, "report-status-v2"))
@@ -2184,7 +2195,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
        }
 }
 
-static const char *pack_lockfile;
+static struct tempfile *pack_lockfile;
 
 static void push_header_arg(struct strvec *args, struct pack_header *hdr)
 {
@@ -2251,6 +2262,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
                        return "unpack-objects abnormal exit";
        } else {
                char hostname[HOST_NAME_MAX + 1];
+               char *lockfile;
 
                strvec_pushl(&child.args, "index-pack", "--stdin", NULL);
                push_header_arg(&child.args, &hdr);
@@ -2280,8 +2292,14 @@ static const char *unpack(int err_fd, struct shallow_info *si)
                status = start_command(&child);
                if (status)
                        return "index-pack fork failed";
-               pack_lockfile = index_pack_lockfile(child.out, NULL);
+
+               lockfile = index_pack_lockfile(child.out, NULL);
+               if (lockfile) {
+                       pack_lockfile = register_tempfile(lockfile);
+                       free(lockfile);
+               }
                close(child.out);
+
                status = finish_command(&child);
                if (status)
                        return "index-pack abnormal exit";
@@ -2509,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:
@@ -2568,8 +2586,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                use_keepalive = KEEPALIVE_ALWAYS;
                execute_commands(commands, unpack_status, &si,
                                 &push_options);
-               if (pack_lockfile)
-                       unlink_or_warn(pack_lockfile);
+               delete_tempfile(&pack_lockfile);
                sigchain_push(SIGPIPE, SIG_IGN);
                if (report_status_v2)
                        report_v2(commands, unpack_status);
@@ -2605,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 270681dcdf40e3c7ff0bf2969340eb1b981cf8e8..df63a5892e71057e342792147fe5d30e13603952 100644 (file)
@@ -1,9 +1,13 @@
 #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"
 
 #define BUILTIN_REFLOG_SHOW_USAGE \
        N_("git reflog [show] [<log-options>] [<ref>]")
@@ -106,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;
@@ -115,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;
@@ -126,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) {
index ee338bf440c6b0647f4c16174166ebd02929a7f4..282782eccdd85691d238e6bd3f3e5b5350304927 100644 (file)
@@ -197,6 +197,8 @@ static int command_loop(const char *child)
 
 int cmd_remote_ext(int argc, const char **argv, const char *prefix)
 {
+       BUG_ON_NON_EMPTY_PREFIX(prefix);
+
        if (argc != 3)
                usage(usage_msg);
 
index b2a3980b1d51b2ec369c7bf758710357b34816c3..9020fab9c580b304d5099e12d35094eb1d1f3874 100644 (file)
@@ -59,6 +59,8 @@ int cmd_remote_fd(int argc, const char **argv, const char *prefix)
        int output_fd = -1;
        char *end;
 
+       BUG_ON_NON_EMPTY_PREFIX(prefix);
+
        if (argc != 3)
                usage(usage_msg);
 
index 729f6f3643add1819942facaae5175555f9c167b..d91bbe728d739e074e5f4fa54f70c186f371c1b7 100644 (file)
@@ -1,6 +1,8 @@
 #include "builtin.h"
 #include "config.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "path.h"
 #include "transport.h"
 #include "remote.h"
 #include "string-list.h"
@@ -9,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"
@@ -166,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")),
@@ -267,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;
@@ -443,7 +445,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
                        info->status = PUSH_STATUS_UPTODATE;
                else if (is_null_oid(&ref->old_oid))
                        info->status = PUSH_STATUS_CREATE;
-               else if (has_object_file(&ref->old_oid) &&
+               else if (repo_has_object_file(the_repository, &ref->old_oid) &&
                         ref_newer(&ref->new_oid, &ref->old_oid))
                        info->status = PUSH_STATUS_FASTFORWARD;
                else
@@ -644,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;
 }
@@ -1493,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 f64937953184fd346923bafed6f7868bd99cded5..97051479e49bf12418dfd70ac42b9bc132b9d571 100644 (file)
@@ -1,9 +1,13 @@
 #include "builtin.h"
-#include "cache.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 "strbuf.h"
 #include "string-list.h"
@@ -11,7 +15,7 @@
 #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"
@@ -55,7 +59,8 @@ struct pack_objects_args {
        int local;
 };
 
-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")) {
@@ -87,12 +92,12 @@ 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
+ * Adds all packs hex strings (pack-$HASH) 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.
  */
@@ -100,40 +105,38 @@ static void collect_pack_filenames(struct string_list *fname_nonkept_list,
                                   struct string_list *fname_kept_list,
                                   const struct string_list *extra_keep)
 {
-       DIR *dir;
-       struct dirent *e;
-       char *fname;
-
-       if (!(dir = opendir(packdir)))
-               return;
+       struct packed_git *p;
+       struct strbuf buf = STRBUF_INIT;
 
-       while ((e = readdir(dir)) != NULL) {
-               size_t len;
+       for (p = get_all_packs(the_repository); p; p = p->next) {
                int i;
+               const char *base;
 
-               if (!strip_suffix(e->d_name, ".pack", &len))
+               if (!p->pack_local)
                        continue;
 
+               base = pack_basename(p);
+
                for (i = 0; i < extra_keep->nr; i++)
-                       if (!fspathcmp(e->d_name, extra_keep->items[i].string))
+                       if (!fspathcmp(base, extra_keep->items[i].string))
                                break;
 
-               fname = xmemdupz(e->d_name, len);
+               strbuf_reset(&buf);
+               strbuf_addstr(&buf, base);
+               strbuf_strip_suffix(&buf, ".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 {
+               if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
+                       string_list_append(fname_kept_list, buf.buf);
+               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 = string_list_append(fname_nonkept_list, buf.buf);
+                       if (p->is_cruft)
                                item->util = (void*)(uintptr_t)CRUFT_PACK;
                }
        }
-       closedir(dir);
 
        string_list_sort(fname_kept_list);
+       strbuf_release(&buf);
 }
 
 static void remove_redundant_pack(const char *dir_name, const char *base_name)
@@ -182,8 +185,9 @@ static void prepare_pack_objects(struct child_process *cmd,
  * Write oid to the given struct child_process's stdin, starting it first if
  * necessary.
  */
-static int write_oid(const struct object_id *oid, struct packed_git *pack,
-                    uint32_t pos, void *data)
+static int write_oid(const struct object_id *oid,
+                    struct packed_git *pack UNUSED,
+                    uint32_t pos UNUSED, void *data)
 {
        struct child_process *cmd = data;
 
@@ -321,7 +325,8 @@ static int geometry_cmp(const void *va, const void *vb)
 }
 
 static void init_pack_geometry(struct pack_geometry **geometry_p,
-                              struct string_list *existing_kept_packs)
+                              struct string_list *existing_kept_packs,
+                              const struct pack_objects_args *args)
 {
        struct packed_git *p;
        struct pack_geometry *geometry;
@@ -331,6 +336,14 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
        geometry = *geometry_p;
 
        for (p = get_all_packs(the_repository); p; p = p->next) {
+               if (args->local && !p->pack_local)
+                       /*
+                        * When asked to only repack local packfiles we skip
+                        * over any packfiles that are borrowed from alternate
+                        * object directories.
+                        */
+                       continue;
+
                if (!pack_kept_objects) {
                        /*
                         * Any pack that has its pack_keep bit set will appear
@@ -444,8 +457,10 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
        geometry->split = split;
 }
 
-static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry)
+static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
 {
+       uint32_t i;
+
        if (!geometry) {
                /*
                 * No geometry means either an all-into-one repack (in which
@@ -460,18 +475,30 @@ static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry
        }
        if (geometry->split == geometry->pack_nr)
                return NULL;
-       return geometry->pack[geometry->pack_nr - 1];
+
+       /*
+        * The preferred pack is the largest pack above the split line. In
+        * other words, it is the largest pack that does not get rolled up in
+        * the geometric repack.
+        */
+       for (i = geometry->pack_nr; i > geometry->split; i--)
+               /*
+                * A pack that is not local would never be included in a
+                * multi-pack index. We thus skip over any non-local packs.
+                */
+               if (geometry->pack[i - 1]->pack_local)
+                       return geometry->pack[i - 1];
+
+       return NULL;
 }
 
-static void clear_pack_geometry(struct pack_geometry *geometry)
+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;
+       free(geometry);
 }
 
 struct midx_snapshot_ref_data {
@@ -554,6 +581,17 @@ static void midx_included_packs(struct string_list *include,
                for (i = geometry->split; i < geometry->pack_nr; i++) {
                        struct packed_git *p = geometry->pack[i];
 
+                       /*
+                        * The multi-pack index never refers to packfiles part
+                        * of an alternate object database, so we skip these.
+                        * While git-multi-pack-index(1) would silently ignore
+                        * them anyway, this allows us to skip executing the
+                        * command completely when we have only non-local
+                        * packfiles.
+                        */
+                       if (!p->pack_local)
+                               continue;
+
                        strbuf_addstr(&buf, pack_basename(p));
                        strbuf_strip_suffix(&buf, ".pack");
                        strbuf_addstr(&buf, ".idx");
@@ -587,7 +625,7 @@ static int write_midx_included_packs(struct string_list *include,
 {
        struct child_process cmd = CHILD_PROCESS_INIT;
        struct string_list_item *item;
-       struct packed_git *largest = get_largest_active_pack(geometry);
+       struct packed_git *preferred = get_preferred_pack(geometry);
        FILE *in;
        int ret;
 
@@ -608,9 +646,9 @@ static int write_midx_included_packs(struct string_list *include,
        if (write_bitmaps)
                strvec_push(&cmd.args, "--bitmap");
 
-       if (largest)
+       if (preferred)
                strvec_pushf(&cmd.args, "--preferred-pack=%s",
-                            pack_basename(largest));
+                            pack_basename(preferred));
 
        if (refs_snapshot)
                strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -770,7 +808,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                N_("same as -a, pack unreachable cruft objects separately"),
                                   PACK_CRUFT),
                OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
-                               N_("with -C, expire objects older than this")),
+                               N_("with --cruft, expire objects older than this")),
                OPT_BOOL('d', NULL, &delete_redundant,
                                N_("remove redundant packs, and run git-prune-packed")),
                OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -849,6 +887,18 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
                die(_(incremental_bitmap_conflict_error));
 
+       if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) {
+               /*
+                * When asked to do a local repack, but we have
+                * packfiles that are inherited from an alternate, then
+                * we cannot guarantee that the multi-pack-index would
+                * have full coverage of all objects. We thus disable
+                * writing bitmaps in that case.
+                */
+               warning(_("disabling bitmap writing, as some objects are not being packed"));
+               write_bitmaps = 0;
+       }
+
        if (write_midx && write_bitmaps) {
                struct strbuf path = STRBUF_INIT;
 
@@ -871,7 +921,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (geometric_factor) {
                if (pack_everything)
                        die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
-               init_pack_geometry(&geometry, &existing_kept_packs);
+               init_pack_geometry(&geometry, &existing_kept_packs, &po_args);
                split_pack_geometry(geometry, geometric_factor);
        }
 
@@ -901,7 +951,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                strvec_push(&cmd.args, "--reflog");
                strvec_push(&cmd.args, "--indexed-objects");
        }
-       if (has_promisor_remote())
+       if (repo_has_promisor_remote(the_repository))
                strvec_push(&cmd.args, "--exclude-promisor-objects");
        if (!write_midx) {
                if (write_bitmaps > 0)
@@ -1176,7 +1226,7 @@ cleanup:
        string_list_clear(&names, 1);
        string_list_clear(&existing_nonkept_packs, 0);
        string_list_clear(&existing_kept_packs, 0);
-       clear_pack_geometry(geometry);
+       free_pack_geometry(geometry);
 
        return ret;
 }
index a29e911d3099be9d327ecc030d68c56fe046a04a..da59600ad22fda16155a278a210478fb55d0d94e 100644 (file)
@@ -8,15 +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-store.h"
+#include "object-file.h"
+#include "object-name.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>"),
@@ -41,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;
 
@@ -54,7 +62,7 @@ static int show_reference(struct repository *r, const char *refname,
                        struct object_id object;
                        enum object_type obj_type, repl_type;
 
-                       if (get_oid(refname, &object))
+                       if (repo_get_oid(r, refname, &object))
                                return error(_("failed to resolve '%s' as a valid ref"), refname);
 
                        obj_type = oid_object_info(r, &object, NULL);
@@ -112,7 +120,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
        base_len = ref.len;
 
        for (p = argv; *p; p++) {
-               if (get_oid(*p, &oid)) {
+               if (repo_get_oid(the_repository, *p, &oid)) {
                        error("failed to resolve '%s' as a valid ref", *p);
                        had_error = 1;
                        continue;
@@ -206,10 +214,10 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
 {
        struct object_id object, repl;
 
-       if (get_oid(object_ref, &object))
+       if (repo_get_oid(the_repository, object_ref, &object))
                return error(_("failed to resolve '%s' as a valid ref"),
                             object_ref);
-       if (get_oid(replace_ref, &repl))
+       if (repo_get_oid(the_repository, replace_ref, &repl))
                return error(_("failed to resolve '%s' as a valid ref"),
                             replace_ref);
 
@@ -320,7 +328,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
        struct object_id old_oid, new_oid, prev;
        struct strbuf ref = STRBUF_INIT;
 
-       if (get_oid(object_ref, &old_oid) < 0)
+       if (repo_get_oid(the_repository, object_ref, &old_oid) < 0)
                return error(_("not a valid object name: '%s'"), object_ref);
 
        type = oid_object_info(the_repository, &old_oid, NULL);
@@ -375,7 +383,7 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
                struct object_id oid;
                struct commit *commit;
 
-               if (get_oid(argv[i], &oid) < 0) {
+               if (repo_get_oid(the_repository, argv[i], &oid) < 0) {
                        strbuf_release(&new_parents);
                        return error(_("not a valid object name: '%s'"),
                                     argv[i]);
@@ -401,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)
 {
@@ -422,7 +430,7 @@ static int check_one_mergetag(struct commit *commit,
        /* iterate over new parents */
        for (i = 1; i < mergetag_data->argc; i++) {
                struct object_id oid;
-               if (get_oid(mergetag_data->argv[i], &oid) < 0)
+               if (repo_get_oid(the_repository, mergetag_data->argv[i], &oid) < 0)
                        return error(_("not a valid object name: '%s'"),
                                     mergetag_data->argv[i]);
                if (oideq(get_tagged_oid(tag), &oid))
@@ -452,15 +460,15 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
        const char *buffer;
        unsigned long size;
 
-       if (get_oid(old_ref, &old_oid) < 0)
+       if (repo_get_oid(the_repository, old_ref, &old_oid) < 0)
                return error(_("not a valid object name: '%s'"), old_ref);
        commit = lookup_commit_reference(the_repository, &old_oid);
        if (!commit)
                return error(_("could not parse %s"), old_ref);
 
-       buffer = get_commit_buffer(commit, &size);
+       buffer = repo_get_commit_buffer(the_repository, commit, &size);
        strbuf_add(&buf, buffer, size);
-       unuse_commit_buffer(commit, buffer);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
 
        if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
                strbuf_release(&buf);
@@ -559,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 94ffb8c21ab1e08f1775ad15315dd689723a2db8..07a9d37275cbbc52cc8cddbae4a6143df2e49a82 100644 (file)
@@ -1,8 +1,9 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "repository.h"
 #include "string-list.h"
 #include "rerere.h"
 #include "xdiff/xdiff.h"
index 0697fa89de22414a58cce94b5f129c9e97d03fa1..4b018d20e3b2200e44a04f1f759837a571e4bc4f 100644 (file)
@@ -9,7 +9,12 @@
  */
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
+#include "advice.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "tag.h"
 #include "object.h"
 #include "diffcore.h"
 #include "tree.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"
+#include "trace2.h"
 #include "dir.h"
 #include "add-interactive.h"
 
@@ -89,7 +100,7 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
 
        if (reset_type == KEEP) {
                struct object_id head_oid;
-               if (get_oid("HEAD", &head_oid))
+               if (repo_get_oid(the_repository, "HEAD", &head_oid))
                        return error(_("You do not have a valid HEAD."));
                if (!fill_tree_descriptor(the_repository, desc + nr, &head_oid))
                        return error(_("Failed to find tree of HEAD."));
@@ -124,7 +135,7 @@ static void print_new_head_line(struct commit *commit)
        struct strbuf buf = STRBUF_INIT;
 
        printf(_("HEAD is now at %s"),
-               find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+               repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
 
        pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
        if (buf.len > 0)
@@ -260,8 +271,8 @@ static void parse_args(struct pathspec *pathspec,
                 * has to be unambiguous. If there is a single argument, it
                 * can not be a tree
                 */
-               else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
-                        (argv[1] && !get_oid_treeish(argv[0], &unused))) {
+               else if ((!argv[1] && !repo_get_oid_committish(the_repository, argv[0], &unused)) ||
+                        (argv[1] && !repo_get_oid_treeish(the_repository, argv[0], &unused))) {
                        /*
                         * Ok, argv[0] looks like a commit/tree; it should not
                         * be a filename.
@@ -288,9 +299,9 @@ static int reset_refs(const char *rev, const struct object_id *oid)
        struct object_id *orig = NULL, oid_orig,
                *old_orig = NULL, oid_old_orig;
 
-       if (!get_oid("ORIG_HEAD", &oid_old_orig))
+       if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
                old_orig = &oid_old_orig;
-       if (!get_oid("HEAD", &oid_orig)) {
+       if (!repo_get_oid(the_repository, "HEAD", &oid_orig)) {
                orig = &oid_orig;
                set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
                update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
@@ -304,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)
@@ -317,7 +329,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        int reset_type = NONE, update_ref_status = 0, quiet = 0;
        int no_refresh = 0;
        int patch_mode = 0, pathspec_file_nul = 0, unborn;
-       const char *rev, *pathspec_from_file = NULL;
+       const char *rev;
+       char *pathspec_from_file = NULL;
        struct object_id oid;
        struct pathspec pathspec;
        int intent_to_add = 0;
@@ -325,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")),
@@ -365,13 +385,14 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
        }
 
-       unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
+       unborn = !strcmp(rev, "HEAD") && repo_get_oid(the_repository, "HEAD",
+                                                     &oid);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
                oidcpy(&oid, the_hash_algo->empty_tree);
        } else if (!pathspec.nr && !patch_mode) {
                struct commit *commit;
-               if (get_oid_committish(rev, &oid))
+               if (repo_get_oid_committish(the_repository, rev, &oid))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
                commit = lookup_commit_reference(the_repository, &oid);
                if (!commit)
@@ -379,7 +400,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                oidcpy(&oid, &commit->object.oid);
        } else {
                struct tree *tree;
-               if (get_oid_treeish(rev, &oid))
+               if (repo_get_oid_treeish(the_repository, rev, &oid))
                        die(_("Failed to resolve '%s' as a valid tree."), rev);
                tree = parse_tree_indirect(&oid);
                if (!tree)
@@ -464,7 +485,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                        char *ref = NULL;
                        int err;
 
-                       dwim_ref(rev, strlen(rev), &dummy, &ref, 0);
+                       repo_dwim_ref(the_repository, rev, strlen(rev),
+                                     &dummy, &ref, 0);
                        if (ref && !starts_with(ref, "refs/"))
                                FREE_AND_NULL(ref);
 
@@ -495,5 +517,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 
 cleanup:
        clear_pathspec(&pathspec);
+       free(pathspec_from_file);
        return update_ref_status;
 }
index d42db0b0cc9fa22ad8674ceddef8d1c735791f37..ff715d6918f004265cf8801879f13fc189f09709 100644 (file)
@@ -1,16 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "commit.h"
 #include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "revision.h"
 #include "list-objects.h"
 #include "list-objects-filter.h"
 #include "list-objects-filter-options.h"
 #include "object.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-file.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"
@@ -38,7 +42,7 @@ static const char rev_list_usage[] =
 "    --tags\n"
 "    --remotes\n"
 "    --stdin\n"
-"    --exclude-hidden=[receive|uploadpack]\n"
+"    --exclude-hidden=[fetch|receive|uploadpack]\n"
 "    --quiet\n"
 "  ordering output:\n"
 "    --topo-order\n"
@@ -134,7 +138,7 @@ static void show_commit(struct commit *commit, void *data)
                if (!revs->graph)
                        fputs(get_revision_mark(revs, commit), stdout);
                if (revs->abbrev_commit && revs->abbrev)
-                       fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
+                       fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, revs->abbrev),
                              stdout);
                else
                        fputs(oid_to_hex(&commit->object.oid), stdout);
@@ -257,7 +261,8 @@ static inline void finish_object__ma(struct object *obj)
        }
 }
 
-static int finish_object(struct object *obj, const char *name, void *cb_data)
+static int finish_object(struct object *obj, const char *name UNUSED,
+                        void *cb_data)
 {
        struct rev_list_info *info = cb_data;
        if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
@@ -362,11 +367,11 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
 
 static int show_object_fast(
        const struct object_id *oid,
-       enum object_type type,
-       int exclude,
-       uint32_t name_hash,
-       struct packed_git *found_pack,
-       off_t found_offset)
+       enum object_type type UNUSED,
+       int exclude UNUSED,
+       uint32_t name_hash UNUSED,
+       struct packed_git *found_pack UNUSED,
+       off_t found_offset UNUSED)
 {
        fprintf(stdout, "%s\n", oid_to_hex(oid));
        return 1;
index e67999e5ebc5ef640fe5dcd45dfa1b4126a9c7a8..fde8861ca4e07990078258843890aef6334dd4c9 100644 (file)
@@ -4,15 +4,23 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.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"
 #include "submodule.h"
 #include "commit-reach.h"
@@ -136,7 +144,9 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
                        struct object_id discard;
                        char *full;
 
-                       switch (dwim_ref(name, strlen(name), &discard, &full, 0)) {
+                       switch (repo_dwim_ref(the_repository, name,
+                                             strlen(name), &discard, &full,
+                                             0)) {
                        case 0:
                                /*
                                 * Not found -- not a ref.  We could
@@ -147,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 */
@@ -162,7 +175,8 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
                }
        }
        else if (abbrev)
-               show_with_type(type, find_unique_abbrev(oid, abbrev));
+               show_with_type(type,
+                              repo_find_unique_abbrev(the_repository, oid, abbrev));
        else
                show_with_type(type, oid_to_hex(oid));
 }
@@ -187,7 +201,7 @@ static int show_default(void)
                struct object_id oid;
 
                def = NULL;
-               if (!get_oid(s, &oid)) {
+               if (!repo_get_oid(the_repository, s, &oid)) {
                        show_rev(NORMAL, &oid, s);
                        return 1;
                }
@@ -211,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;
@@ -279,7 +293,7 @@ static int try_difference(const char *arg)
                return 0;
        }
 
-       if (!get_oid_committish(start, &start_oid) && !get_oid_committish(end, &end_oid)) {
+       if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
                show_rev(NORMAL, &end_oid, end);
                show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
                if (symmetric) {
@@ -291,7 +305,7 @@ static int try_difference(const char *arg)
                                *dotdot = '.';
                                return 0;
                        }
-                       exclude = get_merge_bases(a, b);
+                       exclude = repo_get_merge_bases(the_repository, a, b);
                        while (exclude) {
                                struct commit *commit = pop_commit(&exclude);
                                show_rev(REVERSED, &commit->object.oid, NULL);
@@ -337,7 +351,7 @@ static int try_parent_shorthands(const char *arg)
                return 0;
 
        *dotdot = 0;
-       if (get_oid_committish(arg, &oid) ||
+       if (repo_get_oid_committish(the_repository, arg, &oid) ||
            !(commit = lookup_commit_reference(the_repository, &oid))) {
                *dotdot = '^';
                return 0;
@@ -868,7 +882,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                continue;
                        }
                        if (skip_prefix(arg, "--disambiguate=", &arg)) {
-                               for_each_abbrev(arg, show_abbrev, NULL);
+                               repo_for_each_abbrev(the_repository, arg,
+                                                    show_abbrev, NULL);
                                continue;
                        }
                        if (!strcmp(arg, "--bisect")) {
index 77d2035616efa1aa60b412f024da1a7836df4478..e6f9a1ad26721c450258849cb8e415156052e442 100644 (file)
@@ -1,8 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.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"
@@ -43,20 +45,6 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
        return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
 }
 
-static int option_parse_x(const struct option *opt,
-                         const char *arg, int unset)
-{
-       struct replay_opts **opts_ptr = opt->value;
-       struct replay_opts *opts = *opts_ptr;
-
-       if (unset)
-               return 0;
-
-       ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
-       opts->xopts[opts->xopts_nr++] = xstrdup(arg);
-       return 0;
-}
-
 static int option_parse_m(const struct option *opt,
                          const char *arg, int unset)
 {
@@ -93,7 +81,8 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
                die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
 }
 
-static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
+static int run_sequencer(int argc, const char **argv, const char *prefix,
+                        struct replay_opts *opts)
 {
        const char * const * usage_str = revert_or_cherry_pick_usage(opts);
        const char *me = action_name(opts);
@@ -113,8 +102,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
                             N_("select mainline parent"), option_parse_m),
                OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
                OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
-               OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
-                       N_("option for merge strategy"), option_parse_x),
+               OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
+                       N_("option for merge strategy")),
                { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"),
                  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
                OPT_END()
@@ -140,7 +129,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
                options = parse_options_concat(options, cp_extra);
        }
 
-       argc = parse_options(argc, argv, NULL, options, usage_str,
+       argc = parse_options(argc, argv, prefix, options, usage_str,
                        PARSE_OPT_KEEP_ARGV0 |
                        PARSE_OPT_KEEP_UNKNOWN_OPT);
 
@@ -175,7 +164,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
                                "--signoff", opts->signoff,
                                "--mainline", opts->mainline,
                                "--strategy", opts->strategy ? 1 : 0,
-                               "--strategy-option", opts->xopts ? 1 : 0,
+                               "--strategy-option", opts->xopts.nr ? 1 : 0,
                                "-x", opts->record_origin,
                                "--ff", opts->allow_ff,
                                "--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
@@ -245,7 +234,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
 
        opts.action = REPLAY_REVERT;
        sequencer_init_config(&opts);
-       res = run_sequencer(argc, argv, &opts);
+       res = run_sequencer(argc, argv, prefix, &opts);
        if (res < 0)
                die(_("revert failed"));
        replay_opts_release(&opts);
@@ -259,7 +248,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
 
        opts.action = REPLAY_PICK;
        sequencer_init_config(&opts);
-       res = run_sequencer(argc, argv, &opts);
+       res = run_sequencer(argc, argv, prefix, &opts);
        if (res < 0)
                die(_("cherry-pick failed"));
        replay_opts_release(&opts);
index 8844f90655799b16f59080c8a69ca86fcbb9fd6f..dff819ae5098ff2ee0c72bae00b35da39bf4979d 100644 (file)
 #include "lockfile.h"
 #include "dir.h"
 #include "cache-tree.h"
+#include "gettext.h"
+#include "hash.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"
 
@@ -370,7 +377,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
         */
        if (!force) {
                struct object_id oid;
-               if (get_oid("HEAD", &oid))
+               if (repo_get_oid(the_repository, "HEAD", &oid))
                        oidclr(&oid);
                if (check_local_mod(&oid, index_only))
                        exit(1);
index 4c5d125fa0a1cb4a01deac04637bd4e71763c619..cd6d9e41129a21d7f9c21cebae0a322812ebcbcd 100644 (file)
@@ -1,6 +1,7 @@
 #include "builtin.h"
 #include "config.h"
 #include "commit.h"
+#include "hex.h"
 #include "refs.h"
 #include "pkt-line.h"
 #include "sideband.h"
@@ -15,6 +16,8 @@
 #include "gpg-interface.h"
 #include "gettext.h"
 #include "protocol.h"
+#include "parse-options.h"
+#include "write-or-die.h"
 
 static const char * const send_pack_usage[] = {
        N_("git send-pack [--mirror] [--dry-run] [--force]\n"
@@ -128,10 +131,9 @@ 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)
 {
-       git_gpg_config(k, v, NULL);
-
        if (!strcmp(k, "push.gpgsign")) {
                const char *value;
                if (!git_config_get_value("push.gpgsign", &value)) {
@@ -150,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)
@@ -275,7 +277,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
                fd[0] = 0;
                fd[1] = 1;
        } else {
-               conn = git_connect(fd, dest, receivepack,
+               conn = git_connect(fd, dest, "git-receive-pack", receivepack,
                        args.verbose ? CONNECT_VERBOSE : 0);
        }
 
index 27a87167e19a534c036bb98b1bd268a44c968b58..1307ed2b88a77dbb93d38528b8d39e2b87452d07 100644 (file)
@@ -1,12 +1,15 @@
 #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"
+#include "setup.h"
 #include "shortlog.h"
 #include "parse-options.h"
 #include "trailer.h"
@@ -176,10 +179,11 @@ static void insert_records_from_trailers(struct shortlog *log,
                return;
 
        /*
-        * Using format_commit_message("%B") would be simpler here, but
+        * Using repo_format_commit_message("%B") would be simpler here, but
         * this saves us copying the message.
         */
-       commit_buffer = logmsg_reencode(commit, NULL, ctx->output_encoding);
+       commit_buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+                                            ctx->output_encoding);
        body = strstr(commit_buffer, "\n\n");
        if (!body)
                return;
@@ -202,7 +206,7 @@ static void insert_records_from_trailers(struct shortlog *log,
        trailer_iterator_release(&iter);
 
        strbuf_release(&ident);
-       unuse_commit_buffer(commit, commit_buffer);
+       repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
 }
 
 static int shortlog_needs_dedup(const struct shortlog *log)
@@ -222,7 +226,8 @@ static void insert_records_from_format(struct shortlog *log,
        for_each_string_list_item(item, &log->format) {
                strbuf_reset(&buf);
 
-               format_commit_message(commit, item->string, &buf, ctx);
+               repo_format_commit_message(the_repository, commit,
+                                          item->string, &buf, ctx);
 
                if (!shortlog_needs_dedup(log) || strset_add(dups, buf.buf))
                        insert_one_record(log, buf.buf, oneline);
@@ -248,7 +253,8 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
                if (log->user_format)
                        pretty_print_commit(&ctx, commit, &oneline);
                else
-                       format_commit_message(commit, "%s", &oneline, &ctx);
+                       repo_format_commit_message(the_repository, commit,
+                                                  "%s", &oneline, &ctx);
        }
        oneline_str = oneline.len ? oneline.buf : "<none>";
 
index 358ac3e519a717f1a354b5d6fa00a8fcd8d77ca5..b01ec761d2596c6a524994b99e1ef0aa719735d2 100644 (file)
@@ -1,14 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "pretty.h"
 #include "refs.h"
-#include "builtin.h"
 #include "color.h"
 #include "strvec.h"
+#include "object-name.h"
 #include "parse-options.h"
+#include "repository.h"
 #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"
@@ -240,7 +246,7 @@ static void join_revs(struct commit_list **list_p,
                        parents = parents->next;
                        if ((this_flag & flags) == flags)
                                continue;
-                       parse_commit(p);
+                       repo_parse_commit(the_repository, p);
                        if (mark_seen(p, seen_p) && !still_interesting)
                                extra--;
                        p->object.flags |= flags;
@@ -312,8 +318,8 @@ static void show_one_commit(struct commit *commit, int no_name)
                }
                else
                        printf("[%s] ",
-                              find_unique_abbrev(&commit->object.oid,
-                                                 DEFAULT_ABBREV));
+                              repo_find_unique_abbrev(the_repository, &commit->object.oid,
+                                                      DEFAULT_ABBREV));
        }
        puts(pretty_str);
        strbuf_release(&pretty);
@@ -414,7 +420,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_oid(refname + ofs, &tmp) || !oideq(&tmp, oid))
+       if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
                ofs = 5;
        return append_ref(refname + ofs, oid, 0);
 }
@@ -429,7 +435,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_oid(refname + ofs, &tmp) || !oideq(&tmp, oid))
+       if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
                ofs = 5;
        return append_ref(refname + ofs, oid, 0);
 }
@@ -533,7 +539,7 @@ static int show_independent(struct commit **rev,
 static void append_one_rev(const char *av)
 {
        struct object_id revkey;
-       if (!get_oid(av, &revkey)) {
+       if (!repo_get_oid(the_repository, av, &revkey)) {
                append_ref(av, &revkey, 0);
                return;
        }
@@ -553,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)
@@ -573,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)
@@ -639,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,
@@ -661,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"),
@@ -746,7 +756,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        die(Q_("only %d entry can be shown at one time.",
                               "only %d entries can be shown at one time.",
                               MAX_REVS), MAX_REVS);
-               if (!dwim_ref(*av, strlen(*av), &oid, &ref, 0))
+               if (!repo_dwim_ref(the_repository, *av, strlen(*av), &oid,
+                                  &ref, 0))
                        die(_("no such ref %s"), *av);
 
                /* Has the base been specified? */
@@ -836,13 +847,13 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        die(Q_("cannot handle more than %d rev.",
                               "cannot handle more than %d revs.",
                               MAX_REVS), MAX_REVS);
-               if (get_oid(ref_name[num_rev], &revkey))
+               if (repo_get_oid(the_repository, ref_name[num_rev], &revkey))
                        die(_("'%s' is not a valid ref."), ref_name[num_rev]);
                commit = lookup_commit_reference(the_repository, &revkey);
                if (!commit)
                        die(_("cannot find commit %s (%s)"),
                            ref_name[num_rev], oid_to_hex(&revkey));
-               parse_commit(commit);
+               repo_parse_commit(the_repository, commit);
                mark_seen(commit, &seen);
 
                /* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
@@ -929,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 0e0b9fb95bc11395fecb3718cbe85fd7a0bea903..540dc3dad1c1e3e4308c5058151dfb1dcaee6d21 100644 (file)
@@ -1,7 +1,10 @@
 #include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "pack.h"
 #include "parse-options.h"
+#include "repository.h"
 
 static const char *const show_index_usage[] = {
        "git show-index [--object-format=<hash-algorithm>]",
index 3af6a53ee9750ef5d4e45031ae0088d5e12f37a4..5110814f7960870aa4f1df60965f2234088f859f 100644 (file)
@@ -1,8 +1,10 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
+#include "gettext.h"
+#include "hex.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "object.h"
 #include "tag.h"
 #include "string-list.h"
@@ -26,14 +28,14 @@ static void show_one(const char *refname, const struct object_id *oid)
        const char *hex;
        struct object_id peeled;
 
-       if (!has_object_file(oid))
+       if (!repo_has_object_file(the_repository, oid))
                die("git show-ref: bad ref %s (%s)", refname,
                    oid_to_hex(oid));
 
        if (quiet)
                return;
 
-       hex = find_unique_abbrev(oid, abbrev);
+       hex = repo_find_unique_abbrev(the_repository, oid, abbrev);
        if (hash_only)
                printf("%s\n", hex);
        else
@@ -43,7 +45,7 @@ static void show_one(const char *refname, const struct object_id *oid)
                return;
 
        if (!peel_iterated_oid(oid, &peeled)) {
-               hex = find_unique_abbrev(&peeled, abbrev);
+               hex = repo_find_unique_abbrev(the_repository, &peeled, abbrev);
                printf("%s %s^{}\n", hex, refname);
        }
 }
index c37381549181837ce4afe3659e5790e88485a816..5c8ffb1f7598b056fadcdd8fb98182d34928e6f3 100644 (file)
@@ -1,7 +1,10 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "object-name.h"
 #include "parse-options.h"
 #include "pathspec.h"
 #include "repository.h"
 #include "unpack-trees.h"
 #include "wt-status.h"
 #include "quote.h"
+#include "setup.h"
 #include "sparse-index.h"
 #include "worktree.h"
 
 static const char *empty_base = "";
 
 static char const * const builtin_sparse_checkout_usage[] = {
-       N_("git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"),
+       N_("git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]"),
        NULL
 };
 
@@ -57,6 +61,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
        char *sparse_filename;
        int res;
 
+       setup_work_tree();
        if (!core_apply_sparse_checkout)
                die(_("this worktree is not sparse"));
 
@@ -217,16 +222,14 @@ static int update_working_directory(struct pattern_list *pl)
        o.head_idx = -1;
        o.src_index = r->index;
        o.dst_index = r->index;
-       index_state_init(&o.result, r);
        o.skip_sparse_checkout = 0;
-       o.pl = pl;
 
        setup_work_tree();
 
        repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
 
        setup_unpack_trees_porcelain(&o, "sparse-checkout");
-       result = update_sparsity(&o);
+       result = update_sparsity(&o, pl);
        clear_unpack_trees_porcelain(&o);
 
        if (result == UPDATE_SPARSITY_WARNINGS)
@@ -383,13 +386,7 @@ static int set_config(enum sparse_checkout_mode mode)
        return 0;
 }
 
-static int update_modes(int *cone_mode, int *sparse_index)
-{
-       int mode, record_mode;
-
-       /* Determine if we need to record the mode; ensure sparse checkout on */
-       record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
-
+static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
        /* If not specified, use previous definition of cone mode */
        if (*cone_mode == -1 && core_apply_sparse_checkout)
                *cone_mode = core_sparse_checkout_cone;
@@ -397,12 +394,21 @@ static int update_modes(int *cone_mode, int *sparse_index)
        /* Set cone/non-cone mode appropriately */
        core_apply_sparse_checkout = 1;
        if (*cone_mode == 1 || *cone_mode == -1) {
-               mode = MODE_CONE_PATTERNS;
                core_sparse_checkout_cone = 1;
-       } else {
-               mode = MODE_ALL_PATTERNS;
-               core_sparse_checkout_cone = 0;
+               return MODE_CONE_PATTERNS;
        }
+       core_sparse_checkout_cone = 0;
+       return MODE_ALL_PATTERNS;
+}
+
+static int update_modes(int *cone_mode, int *sparse_index)
+{
+       int mode, record_mode;
+
+       /* Determine if we need to record the mode; ensure sparse checkout on */
+       record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
+
+       mode = update_cone_mode(cone_mode);
        if (record_mode && set_config(mode))
                return 1;
 
@@ -448,6 +454,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
                OPT_END(),
        };
 
+       setup_work_tree();
        repo_read_index(the_repository);
 
        init_opts.cone_mode = -1;
@@ -471,7 +478,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
                return update_working_directory(NULL);
        }
 
-       if (get_oid("HEAD", &oid)) {
+       if (repo_get_oid(the_repository, "HEAD", &oid)) {
                FILE *fp;
 
                /* assume we are in a fresh repo, but update the sparse-checkout file */
@@ -545,7 +552,7 @@ static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
 
 static void add_patterns_from_input(struct pattern_list *pl,
                                    int argc, const char **argv,
-                                   int use_stdin)
+                                   FILE *file)
 {
        int i;
        if (core_sparse_checkout_cone) {
@@ -555,9 +562,9 @@ static void add_patterns_from_input(struct pattern_list *pl,
                hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
                pl->use_cone_patterns = 1;
 
-               if (use_stdin) {
+               if (file) {
                        struct strbuf unquoted = STRBUF_INIT;
-                       while (!strbuf_getline(&line, stdin)) {
+                       while (!strbuf_getline(&line, file)) {
                                if (line.buf[0] == '"') {
                                        strbuf_reset(&unquoted);
                                        if (unquote_c_style(&unquoted, line.buf, NULL))
@@ -579,10 +586,10 @@ static void add_patterns_from_input(struct pattern_list *pl,
                        }
                }
        } else {
-               if (use_stdin) {
+               if (file) {
                        struct strbuf line = STRBUF_INIT;
 
-                       while (!strbuf_getline(&line, stdin)) {
+                       while (!strbuf_getline(&line, file)) {
                                size_t len;
                                char *buf = strbuf_detach(&line, &len);
                                add_pattern(buf, empty_base, 0, pl, 0);
@@ -609,7 +616,8 @@ static void add_patterns_cone_mode(int argc, const char **argv,
        struct pattern_list existing;
        char *sparse_filename = get_sparse_checkout_filename();
 
-       add_patterns_from_input(pl, argc, argv, use_stdin);
+       add_patterns_from_input(pl, argc, argv,
+                               use_stdin ? stdin : NULL);
 
        memset(&existing, 0, sizeof(existing));
        existing.use_cone_patterns = core_sparse_checkout_cone;
@@ -646,7 +654,7 @@ static void add_patterns_literal(int argc, const char **argv,
                                           pl, NULL, 0))
                die(_("unable to load existing sparse-checkout patterns"));
        free(sparse_filename);
-       add_patterns_from_input(pl, argc, argv, use_stdin);
+       add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
 }
 
 static int modify_pattern_list(int argc, const char **argv, int use_stdin,
@@ -665,7 +673,8 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
                break;
 
        case REPLACE:
-               add_patterns_from_input(pl, argc, argv, use_stdin);
+               add_patterns_from_input(pl, argc, argv,
+                                       use_stdin ? stdin : NULL);
                break;
        }
 
@@ -760,6 +769,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
                OPT_END(),
        };
 
+       setup_work_tree();
        if (!core_apply_sparse_checkout)
                die(_("no sparse-checkout to add to"));
 
@@ -806,6 +816,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
                OPT_END(),
        };
 
+       setup_work_tree();
        repo_read_index(the_repository);
 
        set_opts.cone_mode = -1;
@@ -855,6 +866,7 @@ static int sparse_checkout_reapply(int argc, const char **argv,
                OPT_END(),
        };
 
+       setup_work_tree();
        if (!core_apply_sparse_checkout)
                die(_("must be in a sparse-checkout to reapply sparsity patterns"));
 
@@ -898,6 +910,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
         * forcibly return to a dense checkout regardless of initial state.
         */
 
+       setup_work_tree();
        argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_disable_options,
                             builtin_sparse_checkout_disable_usage, 0);
@@ -923,6 +936,91 @@ static int sparse_checkout_disable(int argc, const char **argv,
        return set_config(MODE_NO_PATTERNS);
 }
 
+static char const * const builtin_sparse_checkout_check_rules_usage[] = {
+       N_("git sparse-checkout check-rules [-z] [--skip-checks]"
+          "[--[no-]cone] [--rules-file <file>]"),
+       NULL
+};
+
+static struct sparse_checkout_check_rules_opts {
+       int cone_mode;
+       int null_termination;
+       char *rules_file;
+} check_rules_opts;
+
+static int check_rules(struct pattern_list *pl, int null_terminated) {
+       struct strbuf line = STRBUF_INIT;
+       struct strbuf unquoted = STRBUF_INIT;
+       char *path;
+       int line_terminator = null_terminated ? 0 : '\n';
+       strbuf_getline_fn getline_fn = null_terminated ? strbuf_getline_nul
+               : strbuf_getline;
+       the_repository->index->sparse_checkout_patterns = pl;
+       while (!getline_fn(&line, stdin)) {
+               path = line.buf;
+               if (!null_terminated && line.buf[0] == '"') {
+                       strbuf_reset(&unquoted);
+                       if (unquote_c_style(&unquoted, line.buf, NULL))
+                               die(_("unable to unquote C-style string '%s'"),
+                                       line.buf);
+
+                       path = unquoted.buf;
+               }
+
+               if (path_in_sparse_checkout(path, the_repository->index))
+                       write_name_quoted(path, stdout, line_terminator);
+       }
+       strbuf_release(&line);
+       strbuf_release(&unquoted);
+
+       return 0;
+}
+
+static int sparse_checkout_check_rules(int argc, const char **argv, const char *prefix)
+{
+       static struct option builtin_sparse_checkout_check_rules_options[] = {
+               OPT_BOOL('z', NULL, &check_rules_opts.null_termination,
+                        N_("terminate input and output files by a NUL character")),
+               OPT_BOOL(0, "cone", &check_rules_opts.cone_mode,
+                        N_("when used with --rules-file interpret patterns as cone mode patterns")),
+               OPT_FILENAME(0, "rules-file", &check_rules_opts.rules_file,
+                        N_("use patterns in <file> instead of the current ones.")),
+               OPT_END(),
+       };
+
+       FILE *fp;
+       int ret;
+       struct pattern_list pl = {0};
+       char *sparse_filename;
+       check_rules_opts.cone_mode = -1;
+
+       argc = parse_options(argc, argv, prefix,
+                            builtin_sparse_checkout_check_rules_options,
+                            builtin_sparse_checkout_check_rules_usage,
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+       if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
+               check_rules_opts.cone_mode = 1;
+
+       update_cone_mode(&check_rules_opts.cone_mode);
+       pl.use_cone_patterns = core_sparse_checkout_cone;
+       if (check_rules_opts.rules_file) {
+               fp = xfopen(check_rules_opts.rules_file, "r");
+               add_patterns_from_input(&pl, argc, argv, fp);
+               fclose(fp);
+       } else {
+               sparse_filename = get_sparse_checkout_filename();
+               if (add_patterns_from_file_to_list(sparse_filename, "", 0, &pl,
+                                                  NULL, 0))
+                       die(_("unable to load existing sparse-checkout patterns"));
+               free(sparse_filename);
+       }
+
+       ret = check_rules(&pl, check_rules_opts.null_termination);
+       clear_pattern_list(&pl);
+       return ret;
+}
+
 int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
 {
        parse_opt_subcommand_fn *fn = NULL;
@@ -933,6 +1031,7 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
                OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
                OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
                OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
+               OPT_SUBCOMMAND("check-rules", &fn, sparse_checkout_check_rules),
                OPT_END(),
        };
 
index 3a4f9fd566d27cfea7039f9c92f7a9730f37f912..53e8868ba1cfd7eb9ee27c1505c61b883a9901d9 100644 (file)
@@ -1,6 +1,12 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
+#include "abspath.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
 #include "parse-options.h"
 #include "refs.h"
 #include "lockfile.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"
@@ -201,7 +211,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
 
        revision = info->revision.buf;
 
-       if (get_oid(revision, &info->w_commit))
+       if (repo_get_oid(the_repository, revision, &info->w_commit))
                return error(_("%s is not a valid reference"), revision);
 
        assert_stash_like(info, revision);
@@ -211,7 +221,8 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
        end_of_rev = strchrnul(revision, '@');
        strbuf_add(&symbolic, revision, end_of_rev - revision);
 
-       ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref, 0);
+       ret = repo_dwim_ref(the_repository, symbolic.buf, symbolic.len,
+                           &dummy, &expanded_ref, 0);
        strbuf_release(&symbolic);
        switch (ret) {
        case 0: /* Not found, but valid ref */
@@ -231,7 +242,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
 static int do_clear_stash(void)
 {
        struct object_id obj;
-       if (get_oid(ref_stash, &obj))
+       if (repo_get_oid(the_repository, ref_stash, &obj))
                return 0;
 
        return delete_ref(NULL, ref_stash, &obj, 0);
@@ -427,7 +438,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
         * to the index before a merge was run) and the current index
         * (reflecting the changes brought in by the merge).
         */
-       diff_setup(&diff_opts);
+       repo_diff_setup(the_repository, &diff_opts);
        diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = 0;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -600,7 +611,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
                ret = error(_("could not write index"));
 
        if (ret) {
-               rerere(0);
+               repo_rerere(the_repository, 0);
 
                if (index)
                        fprintf_ln(stderr, _("Index was not unstashed."));
@@ -830,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);
@@ -844,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)
@@ -900,7 +912,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
 
        init_diff_ui_defaults();
        git_config(git_diff_ui_config, NULL);
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
 
        argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
                             PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -961,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);
@@ -1077,19 +1089,18 @@ 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;
 
        /* No initial commit. */
-       if (get_oid("HEAD", &dummy))
+       if (repo_get_oid(the_repository, "HEAD", &dummy))
                return -1;
 
        if (repo_read_index(the_repository) < 0)
                return -1;
 
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        copy_pathspec(&rev.prune_data, ps);
 
        rev.diffopt.flags.quick = 1;
@@ -1099,14 +1110,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;
        }
@@ -1276,7 +1287,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
        struct strbuf diff_output = STRBUF_INIT;
        struct index_state istate = INDEX_STATE_INIT(the_repository);
 
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        copy_pathspec(&rev.prune_data, ps);
 
        set_alternate_index_output(stash_index_path.buf);
@@ -1297,10 +1308,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",
@@ -1355,7 +1363,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
                goto done;
        }
 
-       if (get_oid("HEAD", &info->b_commit)) {
+       if (repo_get_oid(the_repository, "HEAD", &info->b_commit)) {
                if (!quiet)
                        fprintf_ln(stderr, _("You do not have "
                                             "the initial commit yet"));
@@ -1373,8 +1381,9 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
        branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
        if (flags & REF_ISSYMREF)
                skip_prefix(branch_ref, "refs/heads/", &branch_name);
-       head_short_sha1 = find_unique_abbrev(&head_commit->object.oid,
-                                            DEFAULT_ABBREV);
+       head_short_sha1 = repo_find_unique_abbrev(the_repository,
+                                                 &head_commit->object.oid,
+                                                 DEFAULT_ABBREV);
        strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
        pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg);
 
@@ -1465,7 +1474,7 @@ done:
        return ret;
 }
 
-static int create_stash(int argc, const char **argv, const char *prefix)
+static int create_stash(int argc, const char **argv, const char *prefix UNUSED)
 {
        int ret;
        struct strbuf stash_msg_buf = STRBUF_INIT;
index 1e34cf2bebdf5160f0236c1d41a080de5d1744e0..7b700a9fb1c2a355af6ee6935edbeec49f3f4135 100644 (file)
@@ -1,8 +1,11 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "setup.h"
 #include "strbuf.h"
+#include "write-or-die.h"
 
 static void comment_lines(struct strbuf *buf)
 {
@@ -10,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);
 }
 
@@ -55,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 4c173d8b37adfc72ec840fd88ca27e36f432aef3..6f3bf33e615b3162c9109c1884113497ef130809 100644 (file)
@@ -1,12 +1,20 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
+#include "abspath.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"
@@ -18,7 +26,9 @@
 #include "revision.h"
 #include "diffcore.h"
 #include "diff.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "advice.h"
 #include "branch.h"
 #include "list-objects-filter-options.h"
@@ -557,7 +567,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
         * If there are no path args and submodule.active is set then,
         * by default, only initialize 'active' modules.
         */
-       if (!argc && git_config_get_value_multi("submodule.active"))
+       if (!argc && !git_config_get("submodule.active"))
                module_list_active(&list);
 
        info.prefix = prefix;
@@ -619,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 = {
@@ -659,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)) {
@@ -1108,7 +1117,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
                strvec_pushv(&diff_args, info->argv);
 
        git_config(git_diff_basic_config, NULL);
-       init_revisions(&rev, info->prefix);
+       repo_init_revisions(the_repository, &rev, info->prefix);
        rev.abbrev = 0;
        precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
        setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
@@ -1131,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);
@@ -1174,7 +1183,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
        if (!summary_limit)
                return 0;
 
-       if (!get_oid(argc ? argv[0] : "HEAD", &head_oid)) {
+       if (!repo_get_oid(the_repository, argc ? argv[0] : "HEAD", &head_oid)) {
                if (argc) {
                        argv++;
                        argc--;
@@ -1187,7 +1196,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
                        argc--;
                }
        } else {
-               if (get_oid("HEAD", &head_oid))
+               if (repo_get_oid(the_repository, "HEAD", &head_oid))
                        die(_("could not fetch a revision for HEAD"));
        }
 
@@ -2016,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);
@@ -2132,9 +2144,9 @@ static int update_clone_get_next_task(struct child_process *child,
        return 0;
 }
 
-static int update_clone_start_failure(struct strbuf *err,
+static int update_clone_start_failure(struct strbuf *err UNUSED,
                                      void *suc_cb,
-                                     void *idx_task_cb)
+                                     void *idx_task_cb UNUSED)
 {
        struct submodule_update_clone *suc = suc_cb;
 
@@ -2181,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;
 }
 
@@ -2743,7 +2756,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
                 * If there are no path args and submodule.active is set then,
                 * by default, only initialize 'active' modules.
                 */
-               if (!argc && git_config_get_value_multi("submodule.active"))
+               if (!argc && !git_config_get("submodule.active"))
                        module_list_active(&list);
 
                info.prefix = opt.prefix;
@@ -2764,7 +2777,7 @@ cleanup:
        return ret;
 }
 
-static int push_check(int argc, const char **argv, const char *prefix)
+static int push_check(int argc, const char **argv, const char *prefix UNUSED)
 {
        struct remote *remote;
        const char *superproject_head;
@@ -3140,7 +3153,6 @@ static int config_submodule_in_gitmodules(const char *name, const char *var, con
 static void configure_added_submodule(struct add_data *add_data)
 {
        char *key;
-       const char *val;
        struct child_process add_submod = CHILD_PROCESS_INIT;
        struct child_process add_gitmodules = CHILD_PROCESS_INIT;
 
@@ -3185,7 +3197,7 @@ static void configure_added_submodule(struct add_data *add_data)
         * is_submodule_active(), since that function needs to find
         * out the value of "submodule.active" again anyway.
         */
-       if (!git_config_get_string_tmp("submodule.active", &val)) {
+       if (!git_config_get("submodule.active")) {
                /*
                 * If the submodule being added isn't already covered by the
                 * current configured pathspec, set the submodule's active flag
index e00768a8b7ec48b04f670087730495b50353787e..c9defe4d2e4ff057bce4dc31330ae1f964225ede 100644 (file)
@@ -1,8 +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 d428c45dc8d812255336ed5da20804981d3be4ab..3918eacbb57bd9e0d2b90ecbbf6cc07c16fad73b 100644 (file)
@@ -6,11 +6,17 @@
  * Based on git-tag.sh and mktag.c by Linus Torvalds.
  */
 
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "tag.h"
 #include "run-command.h"
 #include "parse-options.h"
@@ -21,6 +27,7 @@
 #include "column.h"
 #include "ref-filter.h"
 #include "date.h"
+#include "write-or-die.h"
 
 static const char * const git_tag_usage[] = {
        N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
@@ -37,6 +44,7 @@ static const char * const git_tag_usage[] = {
 static unsigned int colopts;
 static int force_sign_annotate;
 static int config_sign_tag = -1; /* unspecified */
+static int omit_empty = 0;
 
 static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
                     struct ref_format *format)
@@ -66,6 +74,7 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
                die(_("unable to parse format string"));
        filter->with_commit_tag_algo = 1;
        filter_refs(&array, filter, FILTER_REFS_TAGS);
+       filter_ahead_behind(the_repository, format, &array);
        ref_array_sort(sorting, &array);
 
        for (i = 0; i < array.nr; i++) {
@@ -74,7 +83,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
                if (format_ref_array_item(array.items[i], format, &output, &err))
                        die("%s", err.buf);
                fwrite(output.buf, 1, output.len, stdout);
-               putchar('\n');
+               if (output.len || !omit_empty)
+                       putchar('\n');
        }
 
        strbuf_release(&err);
@@ -111,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;
@@ -137,7 +147,7 @@ static int delete_tags(const char **argv)
                if (!ref_exists(name))
                        printf(_("Deleted tag '%s' (was %s)\n"),
                                item->string + 10,
-                               find_unique_abbrev(oid, DEFAULT_ABBREV));
+                               repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
 
                free(oid);
        }
@@ -145,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;
@@ -178,10 +188,9 @@ 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)
 {
-       int status;
-
        if (!strcmp(var, "tag.gpgsign")) {
                config_sign_tag = git_config_bool(var, value);
                return 0;
@@ -194,9 +203,6 @@ static int git_tag_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       status = git_gpg_config(var, value, cb);
-       if (status)
-               return status;
        if (!strcmp(var, "tag.forcesignannotated")) {
                force_sign_annotate = git_config_bool(var, value);
                return 0;
@@ -204,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)
@@ -215,7 +225,7 @@ static void write_tag_body(int fd, const struct object_id *oid)
        struct strbuf payload = STRBUF_INIT;
        struct strbuf signature = STRBUF_INIT;
 
-       orig = buf = read_object_file(oid, &type, &size);
+       orig = buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (!buf)
                return;
        if (parse_signature(buf, size, &payload, &signature)) {
@@ -266,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)
@@ -294,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) {
@@ -306,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);
                }
@@ -322,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?"));
@@ -336,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)
@@ -366,7 +373,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
                strbuf_addstr(sb, "object of unknown type");
                break;
        case OBJ_COMMIT:
-               if ((buf = read_object_file(oid, &type, &size))) {
+               if ((buf = repo_read_object_file(the_repository, oid, &type, &size))) {
                        subject_len = find_commit_subject(buf, &subject_start);
                        strbuf_insert(sb, sb->len, subject_start, subject_len);
                } else {
@@ -433,11 +440,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        int create_reflog = 0;
        int annotate = 0, force = 0;
        int cmdmode = 0, create_tag_object = 0;
-       const char *msgfile = NULL, *keyid = NULL;
+       char *msgfile = NULL;
+       const char *keyid = NULL;
        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;
@@ -473,6 +481,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
                OPT_MERGED(&filter, N_("print only tags that are merged")),
                OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
+               OPT_BOOL(0, "omit-empty",  &omit_empty,
+                       N_("do not output a newline after empty formatted refs")),
                OPT_REF_SORT(&sorting_options),
                {
                        OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
@@ -487,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;
 
@@ -593,7 +603,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (argc > 2)
                die(_("too many arguments"));
 
-       if (get_oid(object_ref, &object))
+       if (repo_get_oid(the_repository, object_ref, &object))
                die(_("Failed to resolve '%s' as a valid ref."), object_ref);
 
        if (strbuf_check_tag_ref(&ref, tag))
@@ -621,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);
@@ -629,19 +641,30 @@ 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,
-                      find_unique_abbrev(&prev, DEFAULT_ABBREV));
+                      repo_find_unique_abbrev(the_repository, &prev, DEFAULT_ABBREV));
 
 cleanup:
        ref_sorting_release(sorting);
+       ref_filter_clear(&filter);
        strbuf_release(&buf);
        strbuf_release(&ref);
        strbuf_release(&reflog_msg);
        strbuf_release(&msg.buf);
        strbuf_release(&err);
+       free(msgfile);
        return ret;
 }
index 88de32b7d7e66e3d7e1c57775b5f0a1b0b045175..c129e2bb6cbffaf80898c8a9c1c4e49fdeb001a4 100644 (file)
@@ -1,6 +1,8 @@
 #include "builtin.h"
 #include "config.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 
 static char *create_temp_file(struct object_id *oid)
 {
@@ -10,7 +12,7 @@ static char *create_temp_file(struct object_id *oid)
        unsigned long size;
        int fd;
 
-       buf = read_object_file(oid, &type, &size);
+       buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (!buf || type != OBJ_BLOB)
                die("unable to read blob object %s", oid_to_hex(oid));
 
@@ -23,13 +25,13 @@ static char *create_temp_file(struct object_id *oid)
        return path;
 }
 
-int cmd_unpack_file(int argc, const char **argv, const char *prefix)
+int cmd_unpack_file(int argc, const char **argv, const char *prefix UNUSED)
 {
        struct object_id oid;
 
        if (argc != 2 || !strcmp(argv[1], "-h"))
                usage("git unpack-file <blob>");
-       if (get_oid(argv[1], &oid))
+       if (repo_get_oid(the_repository, argv[1], &oid))
                die("Not a valid object name %s", argv[1]);
 
        git_config(git_default_config, NULL);
index 43789b8ef294d8aa3fc9517f65712ac90e1fa60c..32505255a0097b84080dd8af37454aeb01ee8001 100644 (file)
@@ -1,13 +1,18 @@
 #include "builtin.h"
-#include "cache.h"
 #include "bulk-checkin.h"
 #include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.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"
@@ -210,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;
 
@@ -442,7 +448,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                delta_data = get_data(delta_size);
                if (!delta_data)
                        return;
-               if (has_object_file(&base_oid))
+               if (repo_has_object_file(the_repository, &base_oid))
                        ; /* Ok we have this one */
                else if (resolve_against_held(nr, &base_oid,
                                              delta_data, delta_size))
@@ -508,7 +514,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
                return;
 
-       base = read_object_file(&base_oid, &type, &base_size);
+       base = repo_read_object_file(the_repository, &base_oid, &type,
+                                    &base_size);
        if (!base) {
                error("failed to read delta-pack base object %s",
                      oid_to_hex(&base_oid));
@@ -598,12 +605,12 @@ static void unpack_all(void)
                die("unresolved deltas left after unpacking");
 }
 
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
 {
        int i;
        struct object_id oid;
 
-       read_replace_refs = 0;
+       disable_replace_refs();
 
        git_config(git_default_config, NULL);
 
index bf38885d5469b24e1ac64e4d3df74a4e70a3dd7b..aee3cb8cbd3a03cedaf0c3e317e8c860049dbb74 100644 (file)
@@ -4,21 +4,31 @@
  * 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 "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "lockfile.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"
+#include "write-or-die.h"
 
 /*
  * Default to not allowing changes to the list of files. The
index a84e7b47a20620b421b9ab3782cdad4e52bc9e90..242102273eea02a096e7d4c31b5110d592f5d6af 100644 (file)
@@ -1,9 +1,12 @@
-#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"
+#include "repository.h"
 #include "strvec.h"
 
 static const char * const git_update_ref_usage[] = {
@@ -116,7 +119,7 @@ static int parse_next_oid(const char **next, const char *end,
                (*next)++;
                *next = parse_arg(*next, &arg);
                if (arg.len) {
-                       if (get_oid(arg.buf, oid))
+                       if (repo_get_oid(the_repository, arg.buf, oid))
                                goto invalid;
                } else {
                        /* Without -z, an empty value means all zeros: */
@@ -134,7 +137,7 @@ static int parse_next_oid(const char **next, const char *end,
                *next += arg.len;
 
                if (arg.len) {
-                       if (get_oid(arg.buf, oid))
+                       if (repo_get_oid(the_repository, arg.buf, oid))
                                goto invalid;
                } else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
                        /* With -z, treat an empty value as all zeros: */
@@ -549,7 +552,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                refname = argv[0];
                value = argv[1];
                oldval = argv[2];
-               if (get_oid(value, &oid))
+               if (repo_get_oid(the_repository, value, &oid))
                        die("%s: not a valid SHA1", value);
        }
 
@@ -560,7 +563,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                         * must not already exist:
                         */
                        oidclr(&oldoid);
-               else if (get_oid(oldval, &oldoid))
+               else if (repo_get_oid(the_repository, oldval, &oldoid))
                        die("%s: not a valid old SHA1", oldval);
        }
 
index d2239c9ef4dac2b65c3875ce8b8cf0481516615f..1dc3971edeb3837a1479ce519197880d28ba7699 100644 (file)
@@ -1,7 +1,8 @@
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
+#include "gettext.h"
 #include "parse-options.h"
+#include "server-info.h"
 
 static const char * const update_server_info_usage[] = {
        "git update-server-info [-f | --force]",
index 945ee2b4126719764c338ba5a8692b5410765509..1b09e5e1aa3f08e91bf6de731b111864ef405573 100644 (file)
@@ -1,11 +1,12 @@
 /*
  * 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"
 #include "run-command.h"
 #include "strvec.h"
 
@@ -79,6 +80,8 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
 {
        struct child_process writer = CHILD_PROCESS_INIT;
 
+       BUG_ON_NON_EMPTY_PREFIX(prefix);
+
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(upload_archive_usage);
 
index 25b69da2bf2815796d885030c91dbf177a4c4e2e..9b021ef026c28c97ece12b924833dff87c15a103 100644 (file)
@@ -1,9 +1,11 @@
-#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"
 #include "serve.h"
 
@@ -34,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 a80c1df86fd532bb6353b990381bfb050ac5e688..74161bdf1c61b5248150bac284898e3c03c79111 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(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)
@@ -68,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)
+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);
@@ -101,6 +233,7 @@ int cmd_var(int argc, const char **argv, const char *prefix)
                return 1;
 
        printf("%s\n", val);
+       free(val);
 
        return 0;
 }
index 3ebad32b0f14fffb5cfafce87411a534bccdf724..9680b5870130615b7b4432a5ce456279db750aa4 100644 (file)
@@ -5,10 +5,11 @@
  *
  * Based on git-verify-tag
  */
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
-#include "object-store.h"
+#include "config.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "commit.h"
 #include "run-command.h"
@@ -39,7 +40,7 @@ static int verify_commit(const char *name, unsigned flags)
        struct object_id oid;
        struct object *obj;
 
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                return error("commit '%s' not found.", name);
 
        obj = parse_object(the_repository, &oid);
@@ -52,14 +53,6 @@ static int verify_commit(const char *name, unsigned flags)
        return run_gpg_verify((struct commit *)obj, flags);
 }
 
-static int git_verify_commit_config(const char *var, const char *value, void *cb)
-{
-       int status = git_gpg_config(var, value, cb);
-       if (status)
-               return status;
-       return git_default_config(var, value, cb);
-}
-
 int cmd_verify_commit(int argc, const char **argv, const char *prefix)
 {
        int i = 1, verbose = 0, had_error = 0;
@@ -70,7 +63,7 @@ int cmd_verify_commit(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
-       git_config(git_verify_commit_config, NULL);
+       git_config(git_default_config, NULL);
 
        argc = parse_options(argc, argv, prefix, verify_commit_options,
                             verify_commit_usage, PARSE_OPT_KEEP_ARGV0);
index 27d6f75fd8ada57088d33c3c4945b07ed33bbb0e..011dddd2dc329292c363fbcfb10b71c218ffa034 100644 (file)
@@ -1,8 +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 217566952d83ce0c657128d6d5e253bebc72f3bb..d8753270ebee4df6eed4b2dd5037f3fee97eb2c6 100644 (file)
@@ -5,11 +5,12 @@
  *
  * 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"
+#include "object-name.h"
 #include "parse-options.h"
 #include "gpg-interface.h"
 #include "ref-filter.h"
@@ -19,14 +20,6 @@ static const char * const verify_tag_usage[] = {
                NULL
 };
 
-static int git_verify_tag_config(const char *var, const char *value, void *cb)
-{
-       int status = git_gpg_config(var, value, cb);
-       if (status)
-               return status;
-       return git_default_config(var, value, cb);
-}
-
 int cmd_verify_tag(int argc, const char **argv, const char *prefix)
 {
        int i = 1, verbose = 0, had_error = 0;
@@ -39,7 +32,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
-       git_config(git_verify_tag_config, NULL);
+       git_config(git_default_config, NULL);
 
        argc = parse_options(argc, argv, prefix, verify_tag_options,
                             verify_tag_usage, PARSE_OPT_KEEP_ARGV0);
@@ -60,7 +53,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
                struct object_id oid;
                const char *name = argv[i++];
 
-               if (get_oid(name, &oid)) {
+               if (repo_get_oid(the_repository, name, &oid)) {
                        had_error = !!error("tag '%s' not found.", name);
                        continue;
                }
index 254283aa6f5716ab2ab83a477972b4630c056b1b..4cd01842de79fb43b842032eeffb1a181f788c6e 100644 (file)
@@ -1,12 +1,23 @@
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
 #include "checkout.h"
 #include "config.h"
-#include "builtin.h"
+#include "copy.h"
 #include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.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 "sigchain.h"
@@ -17,7 +28,8 @@
 
 #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,
@@ -90,6 +119,7 @@ struct add_opts {
        int detach;
        int quiet;
        int checkout;
+       int orphan;
        const char *keep_locked;
 };
 
@@ -98,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)
@@ -319,7 +350,6 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
 
        if (file_exists(from_file)) {
                struct config_set cs = { { 0 } };
-               const char *core_worktree;
                int bare;
 
                if (safe_create_leading_directories(to_file) ||
@@ -338,7 +368,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
                                to_file, "core.bare", NULL, "true", 0))
                        error(_("failed to unset '%s' in '%s'"),
                                "core.bare", to_file);
-               if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
+               if (!git_configset_get(&cs, "core.worktree") &&
                        git_config_set_in_file_gently(to_file,
                                                        "core.worktree", NULL))
                        error(_("failed to unset '%s' in '%s'"),
@@ -364,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)
 {
@@ -393,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);
@@ -475,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)
@@ -497,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;
@@ -516,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);
@@ -552,7 +602,7 @@ static void print_preparing_worktree_line(int detach,
                else
                        fprintf_ln(stderr, _("Preparing worktree (resetting branch '%s'; was at %s)"),
                                  new_branch,
-                                 find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+                                 repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
        } else if (new_branch) {
                fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
        } else {
@@ -564,14 +614,131 @@ 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)"),
-                                 find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+                                 repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
                }
                strbuf_release(&s);
        }
 }
 
+/**
+ * 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,
+                          const struct object_id *oid,
+                          int flags,
+                          void *cb_data)
+{
+       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 overide 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;
@@ -608,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"),
@@ -616,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")),
@@ -636,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)
@@ -648,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}";
@@ -664,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;
@@ -683,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");
@@ -756,7 +972,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
                strbuf_addstr(&sb, "(bare)");
        else {
                strbuf_addf(&sb, "%-*s ", abbrev_len,
-                               find_unique_abbrev(&wt->head_oid, DEFAULT_ABBREV));
+                               repo_find_unique_abbrev(the_repository, &wt->head_oid, DEFAULT_ABBREV));
                if (wt->is_detached)
                        strbuf_addstr(&sb, "(detached HEAD)");
                else if (wt->head_ref) {
@@ -793,7 +1009,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
 
                if (path_len > *maxlen)
                        *maxlen = path_len;
-               sha1_len = strlen(find_unique_abbrev(&wt[i]->head_oid, *abbrev));
+               sha1_len = strlen(repo_find_unique_abbrev(the_repository, &wt[i]->head_oid, *abbrev));
                if (sha1_len > *abbrev)
                        *abbrev = sha1_len;
        }
@@ -1192,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 078010315f004647f22865db68f5cab63a799f8f..66e83d0ecba04c90d1e12a2529cc40210808035c 100644 (file)
@@ -5,11 +5,14 @@
  */
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "tree.h"
 #include "cache-tree.h"
 #include "parse-options.h"
+#include "repository.h"
 
 static const char * const write_tree_usage[] = {
        N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
@@ -38,6 +41,9 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
        argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
                             write_tree_usage, 0);
 
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
+
        ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags,
                                  tree_prefix);
        switch (ret) {
index 855b68ec23bdb1bdc85c1184a9c144c226f0245c..73bff3a23d27bb2d9b6825bceccc9912aa2c50ce 100644 (file)
@@ -1,8 +1,11 @@
 /*
  * Copyright (c) 2011, Google Inc.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "bulk-checkin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "repository.h"
 #include "csum-file.h"
@@ -11,7 +14,8 @@
 #include "string-list.h"
 #include "tmp-objdir.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 
 static int odb_transaction_nesting;
 
@@ -124,7 +128,7 @@ static int already_written(struct bulk_checkin_packfile *state, struct object_id
        int i;
 
        /* The object may already exist in the repository */
-       if (has_object_file(oid))
+       if (repo_has_object_file(the_repository, oid))
                return 1;
 
        /* Might want to keep the list sorted */
index 8281b9cb159691530eb2f74b46daf535261f6c93..48fe9a6e9171e77aba4f2a3c7ab1edd79e9291b8 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef BULK_CHECKIN_H
 #define BULK_CHECKIN_H
 
-#include "cache.h"
+#include "object.h"
 
 void prepare_loose_object_bulk_checkin(void);
 void fsync_loose_object_bulk_checkin(int fd, const char *filename);
index 8a3c39ce572b6c0fcfcfd07a0fb2f3d6da2bdecc..4b5c49b93d28f080865e23688cc09a0d6dd7d70a 100644 (file)
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "bundle-uri.h"
 #include "bundle.h"
-#include "object-store.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-store-ll.h"
 #include "refs.h"
 #include "run-command.h"
 #include "hashmap.h"
@@ -221,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);
@@ -250,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) {
@@ -792,6 +798,15 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
 
        init_bundle_list(&list);
 
+       /*
+        * Do not fetch an empty bundle URI. An empty bundle URI
+        * could signal that a configured bundle URI has been disabled.
+        */
+       if (!*uri) {
+               result = 0;
+               goto cleanup;
+       }
+
        /* If a bundle is added to this global list, then it is required. */
        list.mode = BUNDLE_MODE_ALL;
 
@@ -859,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;
 
@@ -884,7 +901,7 @@ int bundle_uri_command(struct repository *r,
         * Read all "bundle.*" config lines to the client as key=value
         * packet lines.
         */
-       git_config(config_to_packet_line, &writer);
+       repo_config(r, config_to_packet_line, &writer);
 
        packet_writer_flush(&writer);
 
index 6ab6cd7378d2d633d5d6dc6100e98793799c7f4e..a9744da255c6d527e53e65b71c1f4b9a9d6db4bd 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "lockfile.h"
 #include "bundle.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "object.h"
 #include "commit.h"
@@ -13,6 +16,7 @@
 #include "strvec.h"
 #include "list-objects-filter-options.h"
 #include "connected.h"
+#include "write-or-die.h"
 
 static const char v2_bundle_signature[] = "# v2 git bundle\n";
 static const char v3_bundle_signature[] = "# v3 git bundle\n";
@@ -267,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:
@@ -293,7 +297,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
        if (revs->max_age == -1 && revs->min_age == -1)
                goto out;
 
-       buf = read_object_file(&tag->oid, &type, &size);
+       buf = repo_read_object_file(the_repository, &tag->oid, &type, &size);
        if (!buf)
                goto out;
        line = memmem(buf, size, "\ntagger ", 8);
@@ -382,7 +386,8 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
 
                if (e->item->flags & UNINTERESTING)
                        continue;
-               if (dwim_ref(e->name, strlen(e->name), &oid, &ref, 0) != 1)
+               if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+                                 &oid, &ref, 0) != 1)
                        goto skip_write_ref;
                if (read_ref_full(e->name, RESOLVE_REF_READING, &oid, &flag))
                        flag = 0;
index 9f2bd733a6aa33a7f192a5fd70bd34c61ad9517a..021adbdcbb3d9b482a08b304a80e62264e1a3630 100644 (file)
--- a/bundle.h
+++ b/bundle.h
@@ -2,7 +2,6 @@
 #define BUNDLE_H
 
 #include "strvec.h"
-#include "cache.h"
 #include "string-list.h"
 #include "list-objects-filter-options.h"
 
index 88c2c04f87fe5fcfce380b47f9d9377f9b59d8ef..641427ed410af39be80be22460a103dbad2d3d35 100644 (file)
@@ -1,13 +1,19 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "cache-tree.h"
 #include "bulk-checkin.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
 #include "replace-object.h"
 #include "promisor-remote.h"
 #include "sparse-index.h"
+#include "trace.h"
+#include "trace2.h"
 
 #ifndef DEBUG_CACHE_TREE
 #define DEBUG_CACHE_TREE 0
@@ -229,7 +235,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
        int i;
        if (!it)
                return 0;
-       if (it->entry_count < 0 || !has_object_file(&it->oid))
+       if (it->entry_count < 0 || !repo_has_object_file(the_repository, &it->oid))
                return 0;
        for (i = 0; i < it->subtree_nr; i++) {
                if (!cache_tree_fully_valid(it->down[i]->cache_tree))
@@ -240,7 +246,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
 
 static int must_check_existence(const struct cache_entry *ce)
 {
-       return !(has_promisor_remote() && ce_skip_worktree(ce));
+       return !(repo_has_promisor_remote(the_repository) && ce_skip_worktree(ce));
 }
 
 static int update_one(struct cache_tree *it,
@@ -280,7 +286,7 @@ static int update_one(struct cache_tree *it,
                }
        }
 
-       if (0 <= it->entry_count && has_object_file(&it->oid))
+       if (0 <= it->entry_count && repo_has_object_file(the_repository, &it->oid))
                return it->entry_count;
 
        /*
@@ -386,7 +392,7 @@ static int update_one(struct cache_tree *it,
                ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
                        !must_check_existence(ce);
                if (is_null_oid(oid) ||
-                   (!ce_missing_ok && !has_object_file(oid))) {
+                   (!ce_missing_ok && !repo_has_object_file(the_repository, oid))) {
                        strbuf_release(&buffer);
                        if (expected_missing)
                                return -1;
@@ -434,7 +440,7 @@ static int update_one(struct cache_tree *it,
                struct object_id oid;
                hash_object_file(the_hash_algo, buffer.buf, buffer.len,
                                 OBJ_TREE, &oid);
-               if (has_object_file_with_flags(&oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
+               if (repo_has_object_file_with_flags(the_repository, &oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
                        oidcpy(&it->oid, &oid);
                else
                        to_invalidate = 1;
@@ -470,7 +476,7 @@ int cache_tree_update(struct index_state *istate, int flags)
        if (!istate->cache_tree)
                istate->cache_tree = cache_tree();
 
-       if (!(flags & WRITE_TREE_MISSING_OK) && has_promisor_remote())
+       if (!(flags & WRITE_TREE_MISSING_OK) && repo_has_promisor_remote(the_repository))
                prefetch_cache_entries(istate, must_check_existence);
 
        trace_performance_enter();
@@ -814,14 +820,14 @@ void prime_cache_tree(struct repository *r,
 {
        struct strbuf tree_path = STRBUF_INIT;
 
-       trace2_region_enter("cache-tree", "prime_cache_tree", the_repository);
+       trace2_region_enter("cache-tree", "prime_cache_tree", r);
        cache_tree_free(&istate->cache_tree);
        istate->cache_tree = cache_tree();
 
        prime_cache_tree_rec(r, istate->cache_tree, tree, &tree_path);
        strbuf_release(&tree_path);
        istate->cache_changed |= CACHE_TREE_CHANGED;
-       trace2_region_leave("cache-tree", "prime_cache_tree", the_repository);
+       trace2_region_leave("cache-tree", "prime_cache_tree", r);
 }
 
 /*
index bd97caa07b08f6b5dc62f73485d93d232e179327..faae88be63c2ce012c700af3a88e02e165982a4e 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef CACHE_TREE_H
 #define CACHE_TREE_H
 
-#include "cache.h"
 #include "tree.h"
 #include "tree-walk.h"
 
diff --git a/cache.h b/cache.h
deleted file mode 100644 (file)
index 1278990..0000000
--- a/cache.h
+++ /dev/null
@@ -1,1950 +0,0 @@
-#ifndef CACHE_H
-#define CACHE_H
-
-#include "git-compat-util.h"
-#include "strbuf.h"
-#include "hashmap.h"
-#include "list.h"
-#include "advice.h"
-#include "gettext.h"
-#include "convert.h"
-#include "trace.h"
-#include "trace2.h"
-#include "string-list.h"
-#include "pack-revindex.h"
-#include "hash.h"
-#include "path.h"
-#include "oid-array.h"
-#include "repository.h"
-#include "mem-pool.h"
-
-typedef struct git_zstream {
-       z_stream z;
-       unsigned long avail_in;
-       unsigned long avail_out;
-       unsigned long total_in;
-       unsigned long total_out;
-       unsigned char *next_in;
-       unsigned char *next_out;
-} git_zstream;
-
-void git_inflate_init(git_zstream *);
-void git_inflate_init_gzip_only(git_zstream *);
-void git_inflate_end(git_zstream *);
-int git_inflate(git_zstream *, int flush);
-
-void git_deflate_init(git_zstream *, int level);
-void git_deflate_init_gzip(git_zstream *, int level);
-void git_deflate_init_raw(git_zstream *, int level);
-void git_deflate_end(git_zstream *);
-int git_deflate_abort(git_zstream *);
-int git_deflate_end_gently(git_zstream *);
-int git_deflate(git_zstream *, int flush);
-unsigned long git_deflate_bound(git_zstream *, unsigned long);
-
-#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
-
-/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */
-#define S_IFINVALID     0030000
-
-/*
- * A "directory link" is a link to another git directory.
- *
- * The value 0160000 is not normally a valid mode, and
- * also just happens to be S_IFDIR + S_IFLNK
- */
-#define S_IFGITLINK    0160000
-#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
-
-/*
- * Some mode bits are also used internally for computations.
- *
- * They *must* not overlap with any valid modes, and they *must* not be emitted
- * to outside world - i.e. appear on disk or network. In other words, it's just
- * temporary fields, which we internally use, but they have to stay in-house.
- *
- * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
- *   codebase mode is `unsigned int` which is assumed to be at least 32 bits )
- */
-
-/* used internally in tree-diff */
-#define S_DIFFTREE_IFXMIN_NEQ  0x80000000
-
-
-/*
- * Intensive research over the course of many years has shown that
- * port 9418 is totally unused by anything else. Or
- *
- *     Your search - "port 9418" - did not match any documents.
- *
- * as www.google.com puts it.
- *
- * This port has been properly assigned for git use by IANA:
- * git (Assigned-9418) [I06-050728-0001].
- *
- *     git  9418/tcp   git pack transfer service
- *     git  9418/udp   git pack transfer service
- *
- * with Linus Torvalds <torvalds@osdl.org> as the point of
- * contact. September 2005.
- *
- * See http://www.iana.org/assignments/port-numbers
- */
-#define DEFAULT_GIT_PORT 9418
-
-/*
- * Basic data structures for the directory cache
- */
-
-#define CACHE_SIGNATURE 0x44495243     /* "DIRC" */
-struct cache_header {
-       uint32_t hdr_signature;
-       uint32_t hdr_version;
-       uint32_t hdr_entries;
-};
-
-#define INDEX_FORMAT_LB 2
-#define INDEX_FORMAT_UB 4
-
-/*
- * The "cache_time" is just the low 32 bits of the
- * time. It doesn't matter if it overflows - we only
- * check it for equality in the 32 bits we save.
- */
-struct cache_time {
-       uint32_t sec;
-       uint32_t nsec;
-};
-
-struct stat_data {
-       struct cache_time sd_ctime;
-       struct cache_time sd_mtime;
-       unsigned int sd_dev;
-       unsigned int sd_ino;
-       unsigned int sd_uid;
-       unsigned int sd_gid;
-       unsigned int sd_size;
-};
-
-struct cache_entry {
-       struct hashmap_entry ent;
-       struct stat_data ce_stat_data;
-       unsigned int ce_mode;
-       unsigned int ce_flags;
-       unsigned int mem_pool_allocated;
-       unsigned int ce_namelen;
-       unsigned int index;     /* for link extension */
-       struct object_id oid;
-       char name[FLEX_ARRAY]; /* more */
-};
-
-#define CE_STAGEMASK (0x3000)
-#define CE_EXTENDED  (0x4000)
-#define CE_VALID     (0x8000)
-#define CE_STAGESHIFT 12
-
-/*
- * Range 0xFFFF0FFF in ce_flags is divided into
- * two parts: in-memory flags and on-disk ones.
- * Flags in CE_EXTENDED_FLAGS will get saved on-disk
- * if you want to save a new flag, add it in
- * CE_EXTENDED_FLAGS
- *
- * In-memory only flags
- */
-#define CE_UPDATE            (1 << 16)
-#define CE_REMOVE            (1 << 17)
-#define CE_UPTODATE          (1 << 18)
-#define CE_ADDED             (1 << 19)
-
-#define CE_HASHED            (1 << 20)
-#define CE_FSMONITOR_VALID   (1 << 21)
-#define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
-#define CE_CONFLICTED        (1 << 23)
-
-#define CE_UNPACKED          (1 << 24)
-#define CE_NEW_SKIP_WORKTREE (1 << 25)
-
-/* used to temporarily mark paths matched by pathspecs */
-#define CE_MATCHED           (1 << 26)
-
-#define CE_UPDATE_IN_BASE    (1 << 27)
-#define CE_STRIP_NAME        (1 << 28)
-
-/*
- * Extended on-disk flags
- */
-#define CE_INTENT_TO_ADD     (1 << 29)
-#define CE_SKIP_WORKTREE     (1 << 30)
-/* CE_EXTENDED2 is for future extension */
-#define CE_EXTENDED2         (1U << 31)
-
-#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
-
-/*
- * Safeguard to avoid saving wrong flags:
- *  - CE_EXTENDED2 won't get saved until its semantic is known
- *  - Bits in 0x0000FFFF have been saved in ce_flags already
- *  - Bits in 0x003F0000 are currently in-memory flags
- */
-#if CE_EXTENDED_FLAGS & 0x803FFFFF
-#error "CE_EXTENDED_FLAGS out of range"
-#endif
-
-#define S_ISSPARSEDIR(m) ((m) == S_IFDIR)
-
-/* Forward structure decls */
-struct pathspec;
-struct child_process;
-struct tree;
-
-/*
- * Copy the sha1 and stat state of a cache entry from one to
- * another. But we never change the name, or the hash state!
- */
-static inline void copy_cache_entry(struct cache_entry *dst,
-                                   const struct cache_entry *src)
-{
-       unsigned int state = dst->ce_flags & CE_HASHED;
-       int mem_pool_allocated = dst->mem_pool_allocated;
-
-       /* Don't copy hash chain and name */
-       memcpy(&dst->ce_stat_data, &src->ce_stat_data,
-                       offsetof(struct cache_entry, name) -
-                       offsetof(struct cache_entry, ce_stat_data));
-
-       /* Restore the hash state */
-       dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
-
-       /* Restore the mem_pool_allocated flag */
-       dst->mem_pool_allocated = mem_pool_allocated;
-}
-
-static inline unsigned create_ce_flags(unsigned stage)
-{
-       return (stage << CE_STAGESHIFT);
-}
-
-#define ce_namelen(ce) ((ce)->ce_namelen)
-#define ce_size(ce) cache_entry_size(ce_namelen(ce))
-#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
-#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
-#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
-#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
-#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
-
-#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
-static inline unsigned int create_ce_mode(unsigned int mode)
-{
-       if (S_ISLNK(mode))
-               return S_IFLNK;
-       if (S_ISSPARSEDIR(mode))
-               return S_IFDIR;
-       if (S_ISDIR(mode) || S_ISGITLINK(mode))
-               return S_IFGITLINK;
-       return S_IFREG | ce_permissions(mode);
-}
-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 unsigned int canon_mode(unsigned int mode)
-{
-       if (S_ISREG(mode))
-               return S_IFREG | ce_permissions(mode);
-       if (S_ISLNK(mode))
-               return S_IFLNK;
-       if (S_ISDIR(mode))
-               return S_IFDIR;
-       return S_IFGITLINK;
-}
-
-#define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
-
-#define SOMETHING_CHANGED      (1 << 0) /* unclassified changes go here */
-#define CE_ENTRY_CHANGED       (1 << 1)
-#define CE_ENTRY_REMOVED       (1 << 2)
-#define CE_ENTRY_ADDED         (1 << 3)
-#define RESOLVE_UNDO_CHANGED   (1 << 4)
-#define CACHE_TREE_CHANGED     (1 << 5)
-#define SPLIT_INDEX_ORDERED    (1 << 6)
-#define UNTRACKED_CHANGED      (1 << 7)
-#define FSMONITOR_CHANGED      (1 << 8)
-
-struct split_index;
-struct untracked_cache;
-struct progress;
-struct pattern_list;
-
-enum sparse_index_mode {
-       /*
-        * There are no sparse directories in the index at all.
-        *
-        * Repositories that don't use cone-mode sparse-checkout will
-        * always have their indexes in this mode.
-        */
-       INDEX_EXPANDED = 0,
-
-       /*
-        * The index has already been collapsed to sparse directories
-        * whereever possible.
-        */
-       INDEX_COLLAPSED,
-
-       /*
-        * The sparse directories that exist are outside the
-        * sparse-checkout boundary, but it is possible that some file
-        * entries could collapse to sparse directory entries.
-        */
-       INDEX_PARTIALLY_SPARSE,
-};
-
-struct index_state {
-       struct cache_entry **cache;
-       unsigned int version;
-       unsigned int cache_nr, cache_alloc, cache_changed;
-       struct string_list *resolve_undo;
-       struct cache_tree *cache_tree;
-       struct split_index *split_index;
-       struct cache_time timestamp;
-       unsigned name_hash_initialized : 1,
-                initialized : 1,
-                drop_cache_tree : 1,
-                updated_workdir : 1,
-                updated_skipworktree : 1,
-                fsmonitor_has_run_once : 1;
-       enum sparse_index_mode sparse_index;
-       struct hashmap name_hash;
-       struct hashmap dir_hash;
-       struct object_id oid;
-       struct untracked_cache *untracked;
-       char *fsmonitor_last_update;
-       struct ewah_bitmap *fsmonitor_dirty;
-       struct mem_pool *ce_mem_pool;
-       struct progress *progress;
-       struct repository *repo;
-       struct pattern_list *sparse_checkout_patterns;
-};
-
-/**
- * A "struct index_state istate" must be initialized with
- * INDEX_STATE_INIT or the corresponding index_state_init().
- *
- * If the variable won't be used again, use release_index() to free()
- * its resources. If it needs to be used again use discard_index(),
- * which does the same thing, but will use use index_state_init() at
- * the end. The discard_index() will use its own "istate->repo" as the
- * "r" argument to index_state_init() in that case.
- */
-#define INDEX_STATE_INIT(r) { \
-       .repo = (r), \
-}
-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 */
-
-/*
- * Create cache_entry intended for use in the specified index. Caller
- * is responsible for discarding the cache_entry with
- * `discard_cache_entry`.
- */
-struct cache_entry *make_cache_entry(struct index_state *istate,
-                                    unsigned int mode,
-                                    const struct object_id *oid,
-                                    const char *path,
-                                    int stage,
-                                    unsigned int refresh_options);
-
-struct cache_entry *make_empty_cache_entry(struct index_state *istate,
-                                          size_t name_len);
-
-/*
- * Create a cache_entry that is not intended to be added to an index. If
- * `ce_mem_pool` is not NULL, the entry is allocated within the given memory
- * pool. Caller is responsible for discarding "loose" entries with
- * `discard_cache_entry()` and the memory pool with
- * `mem_pool_discard(ce_mem_pool, should_validate_cache_entries())`.
- */
-struct cache_entry *make_transient_cache_entry(unsigned int mode,
-                                              const struct object_id *oid,
-                                              const char *path,
-                                              int stage,
-                                              struct mem_pool *ce_mem_pool);
-
-struct cache_entry *make_empty_transient_cache_entry(size_t len,
-                                                    struct mem_pool *ce_mem_pool);
-
-/*
- * Discard cache entry.
- */
-void discard_cache_entry(struct cache_entry *ce);
-
-/*
- * Check configuration if we should perform extra validation on cache
- * entries.
- */
-int should_validate_cache_entries(void);
-
-/*
- * Duplicate a cache_entry. Allocate memory for the new entry from a
- * memory_pool. Takes into account cache_entry fields that are meant
- * for managing the underlying memory allocation of the cache_entry.
- */
-struct cache_entry *dup_cache_entry(const struct cache_entry *ce, struct index_state *istate);
-
-/*
- * Validate the cache entries in the index.  This is an internal
- * consistency check that the cache_entry structs are allocated from
- * the expected memory pool.
- */
-void validate_cache_entries(const struct index_state *istate);
-
-/*
- * Bulk prefetch all missing cache entries that are not GITLINKs and that match
- * the given predicate. This function should only be called if
- * has_promisor_remote() returns true.
- */
-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 TYPE_BITS 3
-
-/*
- * Values in this enum (except those outside the 3 bit range) are part
- * of pack file format. See gitformat-pack(5) for more information.
- */
-enum object_type {
-       OBJ_BAD = -1,
-       OBJ_NONE = 0,
-       OBJ_COMMIT = 1,
-       OBJ_TREE = 2,
-       OBJ_BLOB = 3,
-       OBJ_TAG = 4,
-       /* 5 for future expansion */
-       OBJ_OFS_DELTA = 6,
-       OBJ_REF_DELTA = 7,
-       OBJ_ANY,
-       OBJ_MAX
-};
-
-static inline enum object_type object_type(unsigned int mode)
-{
-       return S_ISDIR(mode) ? OBJ_TREE :
-               S_ISGITLINK(mode) ? OBJ_COMMIT :
-               OBJ_BLOB;
-}
-
-/* Double-check local_repo_env below if you add to this list. */
-#define GIT_DIR_ENVIRONMENT "GIT_DIR"
-#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
-#define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
-#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
-#define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
-#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
-#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
-#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
-#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
-#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
-#define CONFIG_ENVIRONMENT "GIT_CONFIG"
-#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
-#define CONFIG_COUNT_ENVIRONMENT "GIT_CONFIG_COUNT"
-#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
-#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
-#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
-#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
-#define GITATTRIBUTES_FILE ".gitattributes"
-#define INFOATTRIBUTES_FILE "info/attributes"
-#define ATTRIBUTE_MACRO_PREFIX "[attr]"
-#define GITMODULES_FILE ".gitmodules"
-#define GITMODULES_INDEX ":.gitmodules"
-#define GITMODULES_HEAD "HEAD:.gitmodules"
-#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
-#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
-#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
-#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
-#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
-#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
-#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
-#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
-#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
-#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
-#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
-#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
-
-/*
- * Environment variable used in handshaking the wire protocol.
- * Contains a colon ':' separated list of keys with optional values
- * 'key[=value]'.  Presence of unknown keys and values must be
- * ignored.
- */
-#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
-/* HTTP header used to handshake the wire protocol */
-#define GIT_PROTOCOL_HEADER "Git-Protocol"
-
-/*
- * This environment variable is expected to contain a boolean indicating
- * whether we should or should not treat:
- *
- *   GIT_DIR=foo.git git ...
- *
- * as if GIT_WORK_TREE=. was given. It's not expected that users will make use
- * of this, but we use it internally to communicate to sub-processes that we
- * are in a bare repo. If not set, defaults to true.
- */
-#define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
-
-/*
- * Repository-local GIT_* environment variables; these will be cleared
- * when git spawns a sub-process that runs inside another repository.
- * The array is NULL-terminated, which makes it easy to pass in the "env"
- * parameter of a run-command invocation, or to do a simple walk.
- */
-extern const char * const local_repo_env[];
-
-void setup_git_env(const char *git_dir);
-
-/*
- * Returns true iff we have a configured git repository (either via
- * setup_git_directory, or in the environment via $GIT_DIR).
- */
-int have_git_dir(void);
-
-extern int is_bare_repository_cfg;
-int is_bare_repository(void);
-int is_inside_git_dir(void);
-extern char *git_work_tree_cfg;
-int is_inside_work_tree(void);
-const char *get_git_dir(void);
-const char *get_git_common_dir(void);
-const char *get_object_directory(void);
-char *get_index_file(void);
-char *get_graft_file(struct repository *r);
-void set_git_dir(const char *path, int make_realpath);
-int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
-int get_common_dir(struct strbuf *sb, const char *gitdir);
-const char *get_git_namespace(void);
-const char *strip_namespace(const char *namespaced_ref);
-const char *get_git_work_tree(void);
-
-/*
- * Return true if the given path is a git directory; note that this _just_
- * looks at the directory itself. If you want to know whether "foo/.git"
- * is a repository, you must feed that path, not just "foo".
- */
-int is_git_directory(const char *path);
-
-/*
- * Return 1 if the given path is the root of a git repository or
- * submodule, else 0. Will not return 1 for bare repositories with the
- * exception of creating a bare repository in "foo/.git" and calling
- * is_git_repository("foo").
- *
- * If we run into read errors, we err on the side of saying "yes, it is",
- * as we usually consider sub-repos precious, and would prefer to err on the
- * side of not disrupting or deleting them.
- */
-int is_nonbare_repository_dir(struct strbuf *path);
-
-#define READ_GITFILE_ERR_STAT_FAILED 1
-#define READ_GITFILE_ERR_NOT_A_FILE 2
-#define READ_GITFILE_ERR_OPEN_FAILED 3
-#define READ_GITFILE_ERR_READ_FAILED 4
-#define READ_GITFILE_ERR_INVALID_FORMAT 5
-#define READ_GITFILE_ERR_NO_PATH 6
-#define READ_GITFILE_ERR_NOT_A_REPO 7
-#define READ_GITFILE_ERR_TOO_LARGE 8
-void read_gitfile_error_die(int error_code, const char *path, const char *dir);
-const char *read_gitfile_gently(const char *path, int *return_error_code);
-#define read_gitfile(path) read_gitfile_gently((path), NULL)
-const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
-#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
-
-void set_git_work_tree(const char *tree);
-
-#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
-
-void setup_work_tree(void);
-/*
- * 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.
- */
-int discover_git_directory(struct strbuf *commondir,
-                          struct strbuf *gitdir);
-const char *setup_git_directory_gently(int *);
-const char *setup_git_directory(void);
-char *prefix_path(const char *prefix, int len, const char *path);
-char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
-
-/*
- * Concatenate "prefix" (if len is non-zero) and "path", with no
- * connecting characters (so "prefix" should end with a "/").
- * Unlike prefix_path, this should be used if the named file does
- * not have to interact with index entry; i.e. name of a random file
- * on the filesystem.
- *
- * The return value is always a newly allocated string (even if the
- * prefix was empty).
- */
-char *prefix_filename(const char *prefix, const char *path);
-
-int check_filename(const char *prefix, const char *name);
-void verify_filename(const char *prefix,
-                    const char *name,
-                    int diagnose_misspelt_rev);
-void verify_non_filename(const char *prefix, const char *name);
-int path_inside_repo(const char *prefix, const char *path);
-
-#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);
-
-void sanitize_stdfds(void);
-int daemonize(void);
-
-#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)
-
-/* 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)
-
-/*
- * Write the index while holding an already-taken lock. Close the lock,
- * and if `COMMIT_LOCK` is given, commit it.
- *
- * Unless a split index is in use, write the index into the lockfile.
- *
- * With a split index, write the shared index to a temporary file,
- * adjust its permissions and rename it into place, then write the
- * split index to the lockfile. If the temporary file for the shared
- * index cannot be created, fall back to the behavior described in
- * the previous paragraph.
- *
- * With `COMMIT_LOCK`, the lock is always committed or rolled back.
- * Without it, the lock is closed, but neither committed nor rolled
- * back.
- *
- * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
- * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
- */
-int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
-
-void discard_index(struct index_state *);
-void move_index_extensions(struct index_state *dst, struct index_state *src);
-int unmerged_index(const struct index_state *);
-
-/**
- * Returns 1 if istate differs from tree, 0 otherwise.  If tree is NULL,
- * compares istate to HEAD.  If tree is NULL and on an unborn branch,
- * returns 1 if there are entries in istate, 0 otherwise.  If an strbuf is
- * provided, the space-separated list of files that differ will be appended
- * to it.
- */
-int repo_index_has_changes(struct repository *repo,
-                          struct tree *tree,
-                          struct strbuf *sb);
-
-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.
- * If the return value is positive (including 0) it is the position of an
- * exact match. If the return value is negative, the negated value minus 1
- * is the position where the entry would be inserted.
- * Example: The current index consists of these files and its stages:
- *
- *   b#0, d#0, f#1, f#3
- *
- * index_name_pos(&index, "a", 1) -> -1
- * index_name_pos(&index, "b", 1) ->  0
- * index_name_pos(&index, "c", 1) -> -2
- * index_name_pos(&index, "d", 1) ->  1
- * index_name_pos(&index, "e", 1) -> -3
- * index_name_pos(&index, "f", 1) -> -3
- * index_name_pos(&index, "g", 1) -> -5
- */
-int index_name_pos(struct index_state *, const char *name, int namelen);
-
-/*
- * Like index_name_pos, returns the position of an entry of the given name in
- * the index if one exists, otherwise returns a negative value where the negated
- * value minus 1 is the position where the index entry would be inserted. Unlike
- * index_name_pos, however, a sparse index is not expanded to find an entry
- * inside a sparse directory.
- */
-int index_name_pos_sparse(struct index_state *, const char *name, int namelen);
-
-/*
- * Determines whether an entry with the given name exists within the
- * given index. The return value is 1 if an exact match is found, otherwise
- * it is 0. Note that, unlike index_name_pos, this function does not expand
- * the index if it is sparse. If an item exists within the full index but it
- * is contained within a sparse directory (and not in the sparse index), 0 is
- * returned.
- */
-int index_entry_exists(struct index_state *, const char *name, int namelen);
-
-/*
- * Some functions return the negative complement of an insert position when a
- * precise match was not found but a position was found where the entry would
- * need to be inserted. This helper protects that logic from any integer
- * underflow.
- */
-static inline int index_pos_to_insert_pos(uintmax_t pos)
-{
-       if (pos > INT_MAX)
-               die("overflow: -1 - %"PRIuMAX, pos);
-       return -1 - (int)pos;
-}
-
-#define ADD_CACHE_OK_TO_ADD 1          /* Ok to add */
-#define ADD_CACHE_OK_TO_REPLACE 2      /* Ok to replace file/directory */
-#define ADD_CACHE_SKIP_DFCHECK 4       /* Ok to skip DF conflict checks */
-#define ADD_CACHE_JUST_APPEND 8                /* Append only */
-#define ADD_CACHE_NEW_ONLY 16          /* Do not replace existing ones */
-#define ADD_CACHE_KEEP_CACHE_TREE 32   /* Do not invalidate cache-tree */
-#define ADD_CACHE_RENORMALIZE 64        /* Pass along HASH_RENORMALIZE */
-int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
-void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
-
-/* Remove entry, return true if there are more entries to go. */
-int remove_index_entry_at(struct index_state *, int pos);
-
-void remove_marked_cache_entries(struct index_state *istate, int invalidate);
-int remove_file_from_index(struct index_state *, const char *path);
-#define ADD_CACHE_VERBOSE 1
-#define ADD_CACHE_PRETEND 2
-#define ADD_CACHE_IGNORE_ERRORS        4
-#define ADD_CACHE_IGNORE_REMOVAL 8
-#define ADD_CACHE_INTENT 16
-/*
- * These two are used to add the contents of the file at path
- * to the index, marking the working tree up-to-date by storing
- * the cached stat info in the resulting cache entry.  A caller
- * that has already run lstat(2) on the path can call
- * add_to_index(), and all others can call add_file_to_index();
- * the latter will do necessary lstat(2) internally before
- * calling the former.
- */
-int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
-int add_file_to_index(struct index_state *, const char *path, int flags);
-
-int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
-int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
-void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
-int index_name_is_other(struct index_state *, const char *, int);
-void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
-
-/* do stat comparison even if CE_VALID is true */
-#define CE_MATCH_IGNORE_VALID          01
-/* do not check the contents but report dirty on racily-clean entries */
-#define CE_MATCH_RACY_IS_DIRTY         02
-/* do stat comparison even if CE_SKIP_WORKTREE is true */
-#define CE_MATCH_IGNORE_SKIP_WORKTREE  04
-/* ignore non-existent files during stat update  */
-#define CE_MATCH_IGNORE_MISSING                0x08
-/* enable stat refresh */
-#define CE_MATCH_REFRESH               0x10
-/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
-#define CE_MATCH_IGNORE_FSMONITOR 0X20
-int is_racy_timestamp(const struct index_state *istate,
-                     const struct cache_entry *ce);
-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);
-
-#define HASH_WRITE_OBJECT 1
-#define HASH_FORMAT_CHECK 2
-#define HASH_RENORMALIZE  4
-#define HASH_SILENT 8
-int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
-int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
-
-/*
- * 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);
-
-void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st);
-
-#define REFRESH_REALLY                   (1 << 0) /* ignore_valid */
-#define REFRESH_UNMERGED                 (1 << 1) /* allow unmerged */
-#define REFRESH_QUIET                    (1 << 2) /* be quiet about it */
-#define REFRESH_IGNORE_MISSING           (1 << 3) /* ignore non-existent */
-#define REFRESH_IGNORE_SUBMODULES        (1 << 4) /* ignore submodules */
-#define REFRESH_IN_PORCELAIN             (1 << 5) /* user friendly output, not "needs update" */
-#define REFRESH_PROGRESS                 (1 << 6) /* show progress bar if stderr is tty */
-#define REFRESH_IGNORE_SKIP_WORKTREE     (1 << 7) /* ignore skip_worktree entries */
-int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
-/*
- * Refresh the index and write it to disk.
- *
- * 'refresh_flags' is passed directly to 'refresh_index()', while
- * 'COMMIT_LOCK | write_flags' is passed to 'write_locked_index()', so
- * the lockfile is always either committed or rolled back.
- *
- * If 'gentle' is passed, errors locking the index are ignored.
- *
- * Return 1 if refreshing the index returns an error, -1 if writing
- * the index to disk fails, 0 on success.
- *
- * Note that if refreshing the index returns an error, we still write
- * out the index (unless locking fails).
- */
-int repo_refresh_and_write_index(struct repository*, unsigned int refresh_flags, unsigned int write_flags, int gentle, const struct pathspec *, char *seen, const char *header_msg);
-
-struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
-
-void set_alternate_index_output(const char *);
-
-extern int verify_index_checksum;
-extern int verify_ce_order;
-
-/* Environment bits from configuration mechanism */
-extern int trust_executable_bit;
-extern int trust_ctime;
-extern int check_stat;
-extern int quote_path_fully;
-extern int has_symlinks;
-extern int minimum_abbrev, default_abbrev;
-extern int ignore_case;
-extern int assume_unchanged;
-extern int prefer_symlink_refs;
-extern int warn_ambiguous_refs;
-extern int warn_on_object_refname_ambiguity;
-extern char *apply_default_whitespace;
-extern char *apply_default_ignorewhitespace;
-extern const char *git_attributes_file;
-extern const char *git_hooks_path;
-extern int zlib_compression_level;
-extern int pack_compression_level;
-extern size_t packed_git_window_size;
-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;
-
-/*
- * Accessors for the core.sharedrepository config which lazy-load the value
- * from the config (if not already set). The "reset" function can be
- * used to unset "set" or cached value, meaning that the value will be loaded
- * fresh from the config file on the next call to get_shared_repository().
- */
-void set_shared_repository(int value);
-int get_shared_repository(void);
-void reset_shared_repository(void);
-
-/*
- * 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;
-
-/*
- * These values are used to help identify parts of a repository to fsync.
- * FSYNC_COMPONENT_NONE identifies data that will not be a persistent part of the
- * repository and so shouldn't be fsynced.
- */
-enum fsync_component {
-       FSYNC_COMPONENT_NONE,
-       FSYNC_COMPONENT_LOOSE_OBJECT            = 1 << 0,
-       FSYNC_COMPONENT_PACK                    = 1 << 1,
-       FSYNC_COMPONENT_PACK_METADATA           = 1 << 2,
-       FSYNC_COMPONENT_COMMIT_GRAPH            = 1 << 3,
-       FSYNC_COMPONENT_INDEX                   = 1 << 4,
-       FSYNC_COMPONENT_REFERENCE               = 1 << 5,
-};
-
-#define FSYNC_COMPONENTS_OBJECTS (FSYNC_COMPONENT_LOOSE_OBJECT | \
-                                 FSYNC_COMPONENT_PACK)
-
-#define FSYNC_COMPONENTS_DERIVED_METADATA (FSYNC_COMPONENT_PACK_METADATA | \
-                                          FSYNC_COMPONENT_COMMIT_GRAPH)
-
-#define FSYNC_COMPONENTS_DEFAULT ((FSYNC_COMPONENTS_OBJECTS | \
-                                  FSYNC_COMPONENTS_DERIVED_METADATA) & \
-                                 ~FSYNC_COMPONENT_LOOSE_OBJECT)
-
-#define FSYNC_COMPONENTS_COMMITTED (FSYNC_COMPONENTS_OBJECTS | \
-                                   FSYNC_COMPONENT_REFERENCE)
-
-#define FSYNC_COMPONENTS_ADDED (FSYNC_COMPONENTS_COMMITTED | \
-                               FSYNC_COMPONENT_INDEX)
-
-#define FSYNC_COMPONENTS_ALL (FSYNC_COMPONENT_LOOSE_OBJECT | \
-                             FSYNC_COMPONENT_PACK | \
-                             FSYNC_COMPONENT_PACK_METADATA | \
-                             FSYNC_COMPONENT_COMMIT_GRAPH | \
-                             FSYNC_COMPONENT_INDEX | \
-                             FSYNC_COMPONENT_REFERENCE)
-
-#ifndef FSYNC_COMPONENTS_PLATFORM_DEFAULT
-#define FSYNC_COMPONENTS_PLATFORM_DEFAULT FSYNC_COMPONENTS_DEFAULT
-#endif
-
-/*
- * A bitmask indicating which components of the repo should be fsynced.
- */
-extern enum fsync_component fsync_components;
-extern int fsync_object_files;
-extern int use_fsync;
-
-enum fsync_method {
-       FSYNC_METHOD_FSYNC,
-       FSYNC_METHOD_WRITEOUT_ONLY,
-       FSYNC_METHOD_BATCH,
-};
-
-extern enum fsync_method fsync_method;
-extern int core_preload_index;
-extern int precomposed_unicode;
-extern int protect_hfs;
-extern int protect_ntfs;
-
-extern int core_apply_sparse_checkout;
-extern int core_sparse_checkout_cone;
-extern int sparse_expect_files_outside_of_patterns;
-
-/*
- * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
- */
-int use_optional_locks(void);
-
-/*
- * The character that begins a commented line in user-editable file
- * that is subject to stripspace.
- */
-extern char comment_line_char;
-extern int auto_comment_line_char;
-
-enum log_refs_config {
-       LOG_REFS_UNSET = -1,
-       LOG_REFS_NONE = 0,
-       LOG_REFS_NORMAL,
-       LOG_REFS_ALWAYS
-};
-extern enum log_refs_config log_all_ref_updates;
-
-enum rebase_setup_type {
-       AUTOREBASE_NEVER = 0,
-       AUTOREBASE_LOCAL,
-       AUTOREBASE_REMOTE,
-       AUTOREBASE_ALWAYS
-};
-
-enum push_default_type {
-       PUSH_DEFAULT_NOTHING = 0,
-       PUSH_DEFAULT_MATCHING,
-       PUSH_DEFAULT_SIMPLE,
-       PUSH_DEFAULT_UPSTREAM,
-       PUSH_DEFAULT_CURRENT,
-       PUSH_DEFAULT_UNSPECIFIED
-};
-
-extern enum rebase_setup_type autorebase;
-extern enum push_default_type push_default;
-
-enum object_creation_mode {
-       OBJECT_CREATION_USES_HARDLINKS = 0,
-       OBJECT_CREATION_USES_RENAMES = 1
-};
-
-extern enum object_creation_mode object_creation_mode;
-
-extern char *notes_ref_name;
-
-extern int grafts_replace_parents;
-
-/*
- * GIT_REPO_VERSION is the version we write by default. The
- * _READ variant is the highest number we know how to
- * handle.
- */
-#define GIT_REPO_VERSION 0
-#define GIT_REPO_VERSION_READ 1
-extern int repository_format_precious_objects;
-extern int repository_format_worktree_config;
-
-/*
- * You _have_ to initialize a `struct repository_format` using
- * `= REPOSITORY_FORMAT_INIT` before calling `read_repository_format()`.
- */
-struct repository_format {
-       int version;
-       int precious_objects;
-       char *partial_clone; /* value of extensions.partialclone */
-       int worktree_config;
-       int is_bare;
-       int hash_algo;
-       int sparse_index;
-       char *work_tree;
-       struct string_list unknown_extensions;
-       struct string_list v1_only_extensions;
-};
-
-/*
- * Always use this to initialize a `struct repository_format`
- * to a well-defined, default state before calling
- * `read_repository()`.
- */
-#define REPOSITORY_FORMAT_INIT \
-{ \
-       .version = -1, \
-       .is_bare = -1, \
-       .hash_algo = GIT_HASH_SHA1, \
-       .unknown_extensions = STRING_LIST_INIT_DUP, \
-       .v1_only_extensions = STRING_LIST_INIT_DUP, \
-}
-
-/*
- * Read the repository format characteristics from the config file "path" into
- * "format" struct. Returns the numeric version. On error, or if no version is
- * found in the configuration, -1 is returned, format->version is set to -1,
- * and all other fields in the struct are set to the default configuration
- * (REPOSITORY_FORMAT_INIT). Always initialize the struct using
- * REPOSITORY_FORMAT_INIT before calling this function.
- */
-int read_repository_format(struct repository_format *format, const char *path);
-
-/*
- * Free the memory held onto by `format`, but not the struct itself.
- * (No need to use this after `read_repository_format()` fails.)
- */
-void clear_repository_format(struct repository_format *format);
-
-/*
- * Verify that the repository described by repository_format is something we
- * can read. If it is, return 0. Otherwise, return -1, and "err" will describe
- * any errors encountered.
- */
-int verify_repository_format(const struct repository_format *format,
-                            struct strbuf *err);
-
-/*
- * Check the repository format version in the path found in get_git_dir(),
- * and die if it is a version we don't understand. Generally one would
- * set_git_dir() before calling this, and use it only for "are we in a valid
- * repo?".
- *
- * If successful and fmt is not NULL, fill fmt with data.
- */
-void check_repository_format(struct repository_format *fmt);
-
-#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
-
-/*
- * Return an abbreviated sha1 unique within this repository's object database.
- * The result will be at least `len` characters long, and will be NUL
- * terminated.
- *
- * The non-`_r` version returns a static buffer which remains valid until 4
- * more calls to find_unique_abbrev are made.
- *
- * The `_r` variant writes to a buffer supplied by the caller, which must be at
- * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes
- * written (excluding the NUL terminator).
- *
- * Note that while this version avoids the static buffer, it is not fully
- * reentrant, as it calls into other non-reentrant git code.
- */
-const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);
-#define find_unique_abbrev(oid, len) repo_find_unique_abbrev(the_repository, oid, len)
-int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);
-#define find_unique_abbrev_r(hex, oid, len) repo_find_unique_abbrev_r(the_repository, hex, oid, 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);
-
-/*
- * NOTE NOTE NOTE!!
- *
- * PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
- * not be changed. Old repositories have core.sharedrepository written in
- * numeric format, and therefore these values are preserved for compatibility
- * reasons.
- */
-enum sharedrepo {
-       PERM_UMASK          = 0,
-       OLD_PERM_GROUP      = 1,
-       OLD_PERM_EVERYBODY  = 2,
-       PERM_GROUP          = 0660,
-       PERM_EVERYBODY      = 0664
-};
-int git_config_perm(const char *var, const char *value);
-int adjust_shared_perm(const char *path);
-
-/*
- * Create the directory containing the named path, using care to be
- * somewhat safe against races. Return one of the scld_error values to
- * indicate success/failure. On error, set errno to describe the
- * problem.
- *
- * SCLD_VANISHED indicates that one of the ancestor directories of the
- * path existed at one point during the function call and then
- * suddenly vanished, probably because another process pruned the
- * directory while we were working.  To be robust against this kind of
- * race, callers might want to try invoking the function again when it
- * returns SCLD_VANISHED.
- *
- * safe_create_leading_directories() temporarily changes path while it
- * is working but restores it before returning.
- * safe_create_leading_directories_const() doesn't modify path, even
- * temporarily. Both these variants adjust the permissions of the
- * created directories to honor core.sharedRepository, so they are best
- * suited for files inside the git dir. For working tree files, use
- * safe_create_leading_directories_no_share() instead, as it ignores
- * the core.sharedRepository setting.
- */
-enum scld_error {
-       SCLD_OK = 0,
-       SCLD_FAILED = -1,
-       SCLD_PERMS = -2,
-       SCLD_EXISTS = -3,
-       SCLD_VANISHED = -4
-};
-enum scld_error safe_create_leading_directories(char *path);
-enum scld_error safe_create_leading_directories_const(const char *path);
-enum scld_error safe_create_leading_directories_no_share(char *path);
-
-int mkdir_in_gitdir(const char *path);
-char *interpolate_path(const char *path, int real_home);
-/* NEEDSWORK: remove this synonym once in-flight topics have migrated */
-#define expand_user_path interpolate_path
-const char *enter_repo(const char *path, int strict);
-static inline int is_absolute_path(const char *path)
-{
-       return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
-}
-int is_directory(const char *);
-char *strbuf_realpath(struct strbuf *resolved, const char *path,
-                     int die_on_error);
-char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
-                               int die_on_error);
-char *real_pathdup(const char *path, int die_on_error);
-const char *absolute_path(const char *path);
-char *absolute_pathdup(const char *path);
-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);
-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);
-
-/*
- * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
- * details.
- */
-int is_ntfs_dotgit(const char *name);
-int is_ntfs_dotgitmodules(const char *name);
-int is_ntfs_dotgitignore(const char *name);
-int is_ntfs_dotgitattributes(const char *name);
-int is_ntfs_dotmailmap(const char *name);
-
-/*
- * Returns true iff "str" could be confused as a command-line option when
- * passed to a sub-program like "ssh". Note that this has nothing to do with
- * shell-quoting, which should be handled separately; we're assuming here that
- * the string makes it verbatim to the sub-program.
- */
-int looks_like_command_line_option(const char *str);
-
-/**
- * Return a newly allocated string with the evaluation of
- * "$XDG_CONFIG_HOME/$subdir/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
- * "$HOME/.config/$subdir/$filename". Return NULL upon error.
- */
-char *xdg_config_home_for(const char *subdir, const char *filename);
-
-/**
- * Return a newly allocated string with the evaluation of
- * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
- * "$HOME/.config/git/$filename". Return NULL upon error.
- */
-char *xdg_config_home(const char *filename);
-
-/**
- * Return a newly allocated string with the evaluation of
- * "$XDG_CACHE_HOME/git/$filename" if $XDG_CACHE_HOME is non-empty, otherwise
- * "$HOME/.cache/git/$filename". Return NULL upon error.
- */
-char *xdg_cache_home(const char *filename);
-
-int git_open_cloexec(const char *name, int flags);
-#define git_open(name) git_open_cloexec(name, O_RDONLY)
-
-/**
- * unpack_loose_header() initializes the data stream needed to unpack
- * a loose object header.
- *
- * Returns:
- *
- * - ULHR_OK on success
- * - ULHR_BAD on error
- * - ULHR_TOO_LONG if the header was too long
- *
- * It will only parse up to MAX_HEADER_LEN bytes unless an optional
- * "hdrbuf" argument is non-NULL. This is intended for use with
- * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error)
- * reporting. The full header will be extracted to "hdrbuf" for use
- * with parse_loose_header(), ULHR_TOO_LONG will still be returned
- * from this function to indicate that the header was too long.
- */
-enum unpack_loose_header_result {
-       ULHR_OK,
-       ULHR_BAD,
-       ULHR_TOO_LONG,
-};
-enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
-                                                   unsigned char *map,
-                                                   unsigned long mapsize,
-                                                   void *buffer,
-                                                   unsigned long bufsiz,
-                                                   struct strbuf *hdrbuf);
-
-/**
- * parse_loose_header() parses the starting "<type> <len>\0" of an
- * object. If it doesn't follow that format -1 is returned. To check
- * the validity of the <type> populate the "typep" in the "struct
- * object_info". It will be OBJ_BAD if the object type is unknown. The
- * parsed <len> can be retrieved via "oi->sizep", and from there
- * passed to unpack_loose_rest().
- */
-struct object_info;
-int parse_loose_header(const char *hdr, struct object_info *oi);
-
-/**
- * With in-core object data in "buf", rehash it to make sure the
- * object name actually matches "oid" to detect object corruption.
- *
- * A negative value indicates an error, usually that the OID is not
- * what we expected, but it might also indicate another error.
- */
-int check_object_signature(struct repository *r, const struct object_id *oid,
-                          void *map, unsigned long size,
-                          enum object_type type);
-
-/**
- * A streaming version of check_object_signature().
- * Try reading the object named with "oid" using
- * the streaming interface and rehash it to do the same.
- */
-int stream_object_signature(struct repository *r, const struct object_id *oid);
-
-int finalize_object_file(const char *tmpfile, const char *filename);
-
-/* Helper to check and "touch" a file */
-int check_and_freshen_file(const char *fn, int freshen);
-
-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]);
-}
-
-/* Convert to/from hex/sha1 representation */
-#define MINIMUM_ABBREV minimum_abbrev
-#define DEFAULT_ABBREV default_abbrev
-
-/* used when the code does not know or care what the default abbrev is */
-#define FALLBACK_DEFAULT_ABBREV 7
-
-struct object_context {
-       unsigned short mode;
-       /*
-        * symlink_path is only used by get_tree_entry_follow_symlinks,
-        * and only for symlinks that point outside the repository.
-        */
-       struct strbuf symlink_path;
-       /*
-        * If GET_OID_RECORD_PATH is set, this will record path (if any)
-        * found when resolving the name. The caller is responsible for
-        * releasing the memory.
-        */
-       char *path;
-};
-
-#define GET_OID_QUIETLY           01
-#define GET_OID_COMMIT            02
-#define GET_OID_COMMITTISH        04
-#define GET_OID_TREE             010
-#define GET_OID_TREEISH          020
-#define GET_OID_BLOB             040
-#define GET_OID_FOLLOW_SYMLINKS 0100
-#define GET_OID_RECORD_PATH     0200
-#define GET_OID_ONLY_TO_DIE    04000
-#define GET_OID_REQUIRE_PATH  010000
-
-#define GET_OID_DISAMBIGUATORS \
-       (GET_OID_COMMIT | GET_OID_COMMITTISH | \
-       GET_OID_TREE | GET_OID_TREEISH | \
-       GET_OID_BLOB)
-
-enum get_oid_result {
-       FOUND = 0,
-       MISSING_OBJECT = -1, /* The requested object is missing */
-       SHORT_NAME_AMBIGUOUS = -2,
-       /* The following only apply when symlinks are followed */
-       DANGLING_SYMLINK = -4, /*
-                               * The initial symlink is there, but
-                               * (transitively) points to a missing
-                               * in-tree file
-                               */
-       SYMLINK_LOOP = -5,
-       NOT_DIR = -6, /*
-                      * Somewhere along the symlink chain, a path is
-                      * requested which contains a file as a
-                      * non-final element.
-                      */
-};
-
-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, ...);
-int repo_get_oid_commit(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_committish(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_tree(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_treeish(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_blob(struct repository *r, const char *str, struct object_id *oid);
-int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid);
-void maybe_die_on_misspelt_object_name(struct repository *repo,
-                                      const char *name,
-                                      const char *prefix);
-enum get_oid_result get_oid_with_context(struct repository *repo, const char *str,
-                                        unsigned flags, struct object_id *oid,
-                                        struct object_context *oc);
-
-#define get_oid(str, oid)              repo_get_oid(the_repository, str, oid)
-#define get_oid_commit(str, oid)       repo_get_oid_commit(the_repository, str, oid)
-#define get_oid_committish(str, oid)   repo_get_oid_committish(the_repository, str, oid)
-#define get_oid_tree(str, oid)         repo_get_oid_tree(the_repository, str, oid)
-#define get_oid_treeish(str, oid)      repo_get_oid_treeish(the_repository, str, oid)
-#define get_oid_blob(str, oid)         repo_get_oid_blob(the_repository, str, oid)
-#define get_oid_mb(str, oid)           repo_get_oid_mb(the_repository, str, oid)
-
-typedef int each_abbrev_fn(const struct object_id *oid, void *);
-int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
-#define for_each_abbrev(prefix, fn, data) repo_for_each_abbrev(the_repository, prefix, fn, data)
-
-int set_disambiguate_hint_config(const char *var, const char *value);
-
-/*
- * 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.
- * 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);
-
-/* 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,
- * and writes the NUL-terminated output to the buffer `out`, which must be at
- * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
- * convenience.
- *
- * The non-`_r` variant returns a static buffer, but uses a ring of 4
- * buffers, making it safe to make multiple calls for a single statement, like:
- *
- *   printf("%s -> %s", hash_to_hex(one), hash_to_hex(two));
- *   printf("%s -> %s", oid_to_hex(one), oid_to_hex(two));
- */
-char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
-char *oid_to_hex_r(char *out, const struct object_id *oid);
-char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *);      /* static buffer result! */
-char *hash_to_hex(const unsigned char *hash);                                          /* same static buffer */
-char *oid_to_hex(const struct object_id *oid);                                         /* same static buffer */
-
-/*
- * Parse a 40-character hexadecimal object ID starting from hex, updating the
- * pointer specified by end when parsing stops.  The resulting object ID is
- * stored in oid.  Returns 0 on success.  Parsing will stop on the first NUL or
- * other invalid character.  end is only updated on success; otherwise, it is
- * unmodified.
- */
-int parse_oid_hex(const char *hex, struct object_id *oid, const char **end);
-
-/* Like parse_oid_hex, but for an arbitrary hash algorithm. */
-int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end,
-                       const struct git_hash_algo *algo);
-
-
-/*
- * These functions work like get_oid_hex and parse_oid_hex, but they will parse
- * a hex value for any algorithm. The algorithm is detected based on the length
- * and the algorithm in use is returned. If this is not a hex object ID in any
- * algorithm, returns GIT_HASH_UNKNOWN.
- */
-int get_oid_hex_any(const char *hex, struct object_id *oid);
-int parse_oid_hex_any(const char *hex, struct object_id *oid, const char **end);
-
-/*
- * This reads short-hand syntax that not only evaluates to a commit
- * object name, but also can act as if the end user spelled the name
- * of the branch from the command line.
- *
- * - "@{-N}" finds the name of the Nth previous branch we were on, and
- *   places the name of the branch in the given buf and returns the
- *   number of characters parsed if successful.
- *
- * - "<branch>@{upstream}" finds the name of the other ref that
- *   <branch> is configured to merge with (missing <branch> defaults
- *   to the current branch), and places the name of the branch in the
- *   given buf and returns the number of characters parsed if
- *   successful.
- *
- * If the input is not of the accepted format, it returns a negative
- * number to signal an error.
- *
- * If the input was ok but there are not N branch switches in the
- * reflog, it returns 0.
- */
-#define INTERPRET_BRANCH_LOCAL (1<<0)
-#define INTERPRET_BRANCH_REMOTE (1<<1)
-#define INTERPRET_BRANCH_HEAD (1<<2)
-struct interpret_branch_name_options {
-       /*
-        * If "allowed" is non-zero, it is a treated as a bitfield of allowable
-        * expansions: local branches ("refs/heads/"), remote branches
-        * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is
-        * allowed, even ones to refs outside of those namespaces.
-        */
-       unsigned allowed;
-
-       /*
-        * If ^{upstream} or ^{push} (or equivalent) is requested, and the
-        * branch in question does not have such a reference, return -1 instead
-        * of die()-ing.
-        */
-       unsigned nonfatal_dangling_mark : 1;
-};
-int repo_interpret_branch_name(struct repository *r,
-                              const char *str, int len,
-                              struct strbuf *buf,
-                              const struct interpret_branch_name_options *options);
-#define interpret_branch_name(str, len, buf, options) \
-       repo_interpret_branch_name(the_repository, str, len, buf, options)
-
-int validate_headref(const char *ref);
-
-int base_name_compare(const char *name1, size_t len1, int mode1,
-                     const char *name2, size_t len2, int mode2);
-int df_name_compare(const char *name1, size_t len1, int mode1,
-                   const char *name2, size_t len2, int mode2);
-int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
-
-void *read_object_with_reference(struct repository *r,
-                                const struct object_id *oid,
-                                enum object_type required_type,
-                                unsigned long *size,
-                                struct object_id *oid_ret);
-
-struct object *repo_peel_to_type(struct repository *r,
-                                const char *name, int namelen,
-                                struct object *o, enum object_type);
-#define peel_to_type(name, namelen, obj, type) \
-       repo_peel_to_type(the_repository, name, namelen, obj, type)
-
-#define IDENT_STRICT          1
-#define IDENT_NO_DATE         2
-#define IDENT_NO_NAME         4
-
-enum want_ident {
-       WANT_BLANK_IDENT,
-       WANT_AUTHOR_IDENT,
-       WANT_COMMITTER_IDENT
-};
-
-const char *git_author_info(int);
-const char *git_committer_info(int);
-const char *fmt_ident(const char *name, const char *email,
-                     enum want_ident whose_ident,
-                     const char *date_str, int);
-const char *fmt_name(enum want_ident);
-const char *ident_default_name(void);
-const char *ident_default_email(void);
-const char *git_editor(void);
-const char *git_sequence_editor(void);
-const char *git_pager(int stdout_is_tty);
-int is_terminal_dumb(void);
-int git_ident_config(const char *, const char *, void *);
-/*
- * Prepare an ident to fall back on if the user didn't configure it.
- */
-void prepare_fallback_ident(const char *name, const char *email);
-void reset_ident_date(void);
-
-struct ident_split {
-       const char *name_begin;
-       const char *name_end;
-       const char *mail_begin;
-       const char *mail_end;
-       const char *date_begin;
-       const char *date_end;
-       const char *tz_begin;
-       const char *tz_end;
-};
-/*
- * Signals an success with 0, but time part of the result may be NULL
- * if the input lacks timestamp and zone
- */
-int split_ident_line(struct ident_split *, const char *, int);
-
-/*
- * Given a commit or tag object buffer and the commit or tag headers, replaces
- * the idents in the headers with their canonical versions using the mailmap mechanism.
- */
-void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);
-
-/*
- * Compare split idents for equality or strict ordering. Note that we
- * compare only the ident part of the line, ignoring any timestamp.
- *
- * Because there are two fields, we must choose one as the primary key; we
- * currently arbitrarily pick the email.
- */
-int ident_cmp(const struct ident_split *, const struct ident_split *);
-
-struct cache_def {
-       struct strbuf path;
-       int flags;
-       int track_flags;
-       int prefix_len_stat_func;
-};
-#define CACHE_DEF_INIT { \
-       .path = STRBUF_INIT, \
-}
-static inline void cache_def_clear(struct cache_def *cache)
-{
-       strbuf_release(&cache->path);
-}
-
-int has_symlink_leading_path(const char *name, int len);
-int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
-int check_leading_path(const char *name, int len, int warn_on_lstat_err);
-int has_dirs_only_path(const char *name, int len, int prefix_len);
-void invalidate_lstat_cache(void);
-void schedule_dir_for_removal(const char *name, int len);
-void remove_scheduled_dirs(void);
-
-struct pack_window {
-       struct pack_window *next;
-       unsigned char *base;
-       off_t offset;
-       size_t len;
-       unsigned int last_used;
-       unsigned int inuse_cnt;
-};
-
-struct pack_entry {
-       off_t offset;
-       struct packed_git *p;
-};
-
-/*
- * Create a temporary file rooted in the object database directory, or
- * die on failure. The filename is taken from "pattern", which should have the
- * usual "XXXXXX" trailer, and the resulting filename is written into the
- * "template" buffer. Returns the open descriptor.
- */
-int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
-
-/*
- * Create a pack .keep file named "name" (which should generally be the output
- * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
- * error.
- */
-int odb_pack_keep(const char *name);
-
-/*
- * Set this to 0 to prevent oid_object_info_extended() from fetching missing
- * blobs. This has a difference only if extensions.partialClone is set.
- *
- * Its default value is 1.
- */
-extern int fetch_if_missing;
-
-/* Dumb servers support */
-int update_server_info(int);
-
-const char *get_log_output_encoding(void);
-const char *get_commit_output_encoding(void);
-
-int committer_ident_sufficiently_given(void);
-int author_ident_sufficiently_given(void);
-
-extern const char *git_commit_encoding;
-extern const char *git_log_output_encoding;
-extern const char *git_mailmap_file;
-extern const char *git_mailmap_blob;
-
-/* IO helper functions */
-void maybe_flush_or_die(FILE *, const char *);
-__attribute__((format (printf, 2, 3)))
-void fprintf_or_die(FILE *, const char *fmt, ...);
-void fwrite_or_die(FILE *f, const void *buf, size_t count);
-void fflush_or_die(FILE *f);
-
-#define COPY_READ_ERROR (-2)
-#define COPY_WRITE_ERROR (-3)
-int copy_fd(int ifd, int ofd);
-int copy_file(const char *dst, const char *src, int mode);
-int copy_file_with_time(const char *dst, const char *src, int mode);
-
-void write_or_die(int fd, const void *buf, size_t count);
-void fsync_or_die(int fd, const char *);
-int fsync_component(enum fsync_component component, int fd);
-void fsync_component_or_die(enum fsync_component component, int fd, const char *msg);
-
-static inline int batch_fsync_enabled(enum fsync_component component)
-{
-       return (fsync_components & component) && (fsync_method == FSYNC_METHOD_BATCH);
-}
-
-ssize_t read_in_full(int fd, void *buf, size_t count);
-ssize_t write_in_full(int fd, const void *buf, size_t count);
-ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
-
-static inline ssize_t write_str_in_full(int fd, const char *str)
-{
-       return write_in_full(fd, str, strlen(str));
-}
-
-/**
- * Open (and truncate) the file at path, write the contents of buf to it,
- * and close it. Dies if any errors are encountered.
- */
-void write_file_buf(const char *path, const char *buf, size_t len);
-
-/**
- * Like write_file_buf(), but format the contents into a buffer first.
- * Additionally, write_file() will append a newline if one is not already
- * present, making it convenient to write text files:
- *
- *   write_file(path, "counter: %d", ctr);
- */
-__attribute__((format (printf, 2, 3)))
-void write_file(const char *path, const char *fmt, ...);
-
-/* pager.c */
-void setup_pager(void);
-int pager_in_use(void);
-extern int pager_use_color;
-int term_columns(void);
-void term_clear_line(void);
-int decimal_width(uintmax_t);
-int check_pager_config(const char *cmd);
-void prepare_pager_args(struct child_process *, const char *pager);
-
-extern const char *editor_program;
-extern const char *askpass_program;
-extern const char *excludes_file;
-
-/* base85 */
-int decode_85(char *dst, const char *line, int linelen);
-void encode_85(char *buf, const unsigned char *data, int bytes);
-
-/* pkt-line.c */
-void packet_trace_identity(const char *prog);
-
-/* 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);
-
-/* diff.c */
-extern int diff_auto_refresh_index;
-
-/* match-trees.c */
-void shift_tree(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, int);
-void shift_tree_by(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, const char *);
-
-/*
- * whitespace rules.
- * used by both diff and apply
- * last two digits are tab width
- */
-#define WS_BLANK_AT_EOL         0100
-#define WS_SPACE_BEFORE_TAB     0200
-#define WS_INDENT_WITH_NON_TAB  0400
-#define WS_CR_AT_EOL           01000
-#define WS_BLANK_AT_EOF        02000
-#define WS_TAB_IN_INDENT       04000
-#define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
-#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
-#define WS_TAB_WIDTH_MASK        077
-/* All WS_* -- when extended, adapt diff.c emit_symbol */
-#define WS_RULE_MASK           07777
-extern unsigned whitespace_rule_cfg;
-unsigned whitespace_rule(struct index_state *, const char *);
-unsigned parse_whitespace_rule(const char *);
-unsigned ws_check(const char *line, int len, unsigned ws_rule);
-void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
-char *whitespace_error_string(unsigned ws);
-void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
-int ws_blank_line(const char *line, int len);
-#define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
-
-/* ls-files */
-void overlay_tree_on_index(struct index_state *istate,
-                          const char *tree_name, const char *prefix);
-
-/* setup.c */
-struct startup_info {
-       int have_repository;
-       const char *prefix;
-       const char *original_cwd;
-};
-extern struct startup_info *startup_info;
-extern const char *tmp_original_cwd;
-
-/* 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);
-
-int versioncmp(const char *s1, const char *s2);
-
-/*
- * Create a directory and (if share is nonzero) adjust its permissions
- * according to the shared_repository setting. Only use this for
- * directories under $GIT_DIR.  Don't use it for working tree
- * directories.
- */
-void safe_create_dir(const char *dir, int share);
-
-/*
- * Should we print an ellipsis after an abbreviated SHA-1 value
- * when doing diff-raw output or indicating a detached HEAD?
- */
-int print_sha1_ellipsis(void);
-
-/* Return 1 if the file is empty or does not exists, 0 otherwise. */
-int is_empty_or_missing_file(const char *filename);
-
-#endif /* CACHE_H */
index 336e46dbba5a06e7d9b5fdb5dd6f3c7bdd971186..c1cc30a5dc7edaadfa69877b4a8f7a6e3a92ffdb 100644 (file)
--- a/cbtree.c
+++ b/cbtree.c
@@ -4,6 +4,7 @@
  * Based on Adam Langley's adaptation of Dan Bernstein's public domain code
  * git clone https://github.com/agl/critbit.git
  */
+#include "git-compat-util.h"
 #include "cbtree.h"
 
 static struct cb_node *cb_node_of(const void *p)
index 0be14fb7ee4276dff338eb27b35c68973dd2c4b2..43193abdda23cef279f9e9cee99370509611f7c5 100644 (file)
--- a/cbtree.h
+++ b/cbtree.h
@@ -14,8 +14,6 @@
 #ifndef CBTREE_H
 #define CBTREE_H
 
-#include "git-compat-util.h"
-
 struct cb_node;
 struct cb_node {
        struct cb_node *child[2];
index 5f7f2c2ac236f7aab50f0bbdc46324fd56213be9..0d7bc0460747b2973f913b746c4b9ef0ba6b9028 100644 (file)
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "chdir-notify.h"
 #include "list.h"
+#include "path.h"
 #include "strbuf.h"
+#include "trace.h"
 
 struct chdir_notify_entry {
        const char *name;
index 2e39dae684f8f0a048d172f36b21740f92e7de57..4256e71a7c41cd4fdfbcd832727c21548b52b740 100644 (file)
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "object-name.h"
 #include "remote.h"
 #include "refspec.h"
+#include "repository.h"
 #include "checkout.h"
 #include "config.h"
+#include "strbuf.h"
 
 struct tracking_name_data {
        /* const */ char *src_ref;
@@ -23,7 +26,7 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
        memset(&query, 0, sizeof(struct refspec_item));
        query.src = cb->src_ref;
        if (remote_find_tracking(remote, &query) ||
-           get_oid(query.dst, cb->dst_oid)) {
+           repo_get_oid(the_repository, query.dst, cb->dst_oid)) {
                free(query.dst);
                return 0;
        }
index 1152133bd77a773f40afd6c3477224e051318e0c..3c514a5ab4f923db5e412fe5552960d8382ea9f5 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef CHECKOUT_H
 #define CHECKOUT_H
 
-#include "cache.h"
+#include "hash-ll.h"
 
 /*
  * Check if the branch name uniquely matches a branch name on a remote
index 0275b74a895a17bb62b7fe12299e6f12aa503d92..140dfa0dcc4629fec59f723d025ec36019ff29eb 100644 (file)
@@ -1,6 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "chunk-format.h"
 #include "csum-file.h"
+#include "gettext.h"
+#include "hash.h"
+#include "trace2.h"
 
 /*
  * When writing a chunk-based file format, collect the chunks in
index 7885aa084878dde2f2786545b7edc05e7d3fee24..c7794e84adda364bc0ad14a3d1d61467d73eaadd 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef CHUNK_FORMAT_H
 #define CHUNK_FORMAT_H
 
-#include "git-compat-util.h"
-#include "hash.h"
+#include "hash-ll.h"
 
 struct hashfile;
 struct chunkfile;
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 b098e10f52aed2f9d8928958fd393cbd574ddf8b..2528f25e31d3c860d1f2dc435af320a4f1b4973c 100755 (executable)
@@ -27,8 +27,9 @@ linux-TEST-vars)
        export GIT_TEST_MULTI_PACK_INDEX=1
        export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
        export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
-       export GIT_TEST_WRITE_REV_INDEX=1
+       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 f05d8a81d72115edbf47d34950a31615a15ea98e..b24b19566b99eb498859ed315b74cabcf6df37c1 100644 (file)
--- a/color.c
+++ b/color.c
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "color.h"
+#include "editor.h"
+#include "gettext.h"
+#include "hex.h"
+#include "pager.h"
+#include "strbuf.h"
 
 static int git_use_color_default = GIT_COLOR_AUTO;
 int color_stdout_is_tty = -1;
@@ -425,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 fbf88639aaed931602b203f012468cdeefda284f..ff2f0abf39930c85a515283625a98152d85bc492 100644 (file)
--- a/column.c
+++ b/column.c
@@ -1,7 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "column.h"
 #include "string-list.h"
+#include "pager.h"
 #include "parse-options.h"
 #include "run-command.h"
 #include "utf8.h"
index 1a39b5dde0946df0c1e36c7b1f4c48552885985a..f90f442482932e618cc7399924c00ddde8c50eaf 100644 (file)
@@ -1,14 +1,19 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "object-store-ll.h"
 #include "commit.h"
+#include "convert.h"
 #include "blob.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-name.h"
 #include "quote.h"
 #include "xdiff-interface.h"
 #include "xdiff/xmacros.h"
 #include "log-tree.h"
 #include "refs.h"
+#include "tree.h"
 #include "userdiff.h"
 #include "oid-array.h"
 #include "revision.h"
@@ -332,7 +337,7 @@ static char *grab_blob(struct repository *r,
                *size = fill_textconv(r, textconv, df, &blob);
                free_filespec(df);
        } else {
-               blob = read_object_file(oid, &type, size);
+               blob = repo_read_object_file(r, oid, &type, size);
                if (type != OBJ_BLOB)
                        die("object '%s' is not a blob!", oid_to_hex(oid));
        }
@@ -948,11 +953,11 @@ static void show_combined_header(struct combine_diff_path *elem,
                         "", elem->path, line_prefix, c_meta, c_reset);
        printf("%s%sindex ", line_prefix, c_meta);
        for (i = 0; i < num_parent; i++) {
-               abb = find_unique_abbrev(&elem->parent[i].oid,
-                                        abbrev);
+               abb = repo_find_unique_abbrev(the_repository,
+                                             &elem->parent[i].oid, abbrev);
                printf("%s%s", i ? "," : "", abb);
        }
-       abb = find_unique_abbrev(&elem->oid, abbrev);
+       abb = repo_find_unique_abbrev(the_repository, &elem->oid, abbrev);
        printf("..%s%s\n", abb, c_reset);
 
        if (mode_differs) {
index c11b59f28b3164cee21ab972088c32082d8f5bb6..9e6eaa8a46b3663979acc32c5b5a2d402d8771ee 100644 (file)
@@ -1,5 +1,7 @@
 #include "git-compat-util.h"
 #include "config.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "pack.h"
 #include "packfile.h"
@@ -9,7 +11,10 @@
 #include "revision.h"
 #include "hash-lookup.h"
 #include "commit-graph.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "path.h"
 #include "alloc.h"
 #include "hashmap.h"
 #include "replace-object.h"
@@ -19,6 +24,7 @@
 #include "shallow.h"
 #include "json-writer.h"
 #include "trace2.h"
+#include "tree.h"
 #include "chunk-format.h"
 
 void git_test_write_commit_graph_or_die(void)
@@ -116,11 +122,19 @@ timestamp_t commit_graph_generation(const struct commit *c)
        struct commit_graph_data *data =
                commit_graph_data_slab_peek(&commit_graph_data_slab, c);
 
-       if (!data)
-               return GENERATION_NUMBER_INFINITY;
-       else if (data->graph_pos == COMMIT_NOT_FROM_GRAPH)
-               return GENERATION_NUMBER_INFINITY;
+       if (data && data->generation)
+               return data->generation;
 
+       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;
 }
 
@@ -200,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;
@@ -478,7 +490,7 @@ static int add_graph_to_chain(struct commit_graph *g,
 
                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;
                }
@@ -488,8 +500,15 @@ static int add_graph_to_chain(struct commit_graph *g,
 
        g->base_graph = chain;
 
-       if (chain)
+       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;
+       }
 
        return 1;
 }
@@ -743,7 +762,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,
@@ -779,7 +798,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;
@@ -789,14 +808,14 @@ 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);
+                       graph_data->generation = item->date + get_be64(g->chunk_generation_data_overflow + st_mult(8, offset_pos));
                } else
                        graph_data->generation = item->date + offset;
        } else
@@ -827,7 +846,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;
 
@@ -849,7 +868,7 @@ static int fill_commit_in_graph(struct repository *r,
        }
 
        parent_data_ptr = (uint32_t*)(g->chunk_extra_edges +
-                         4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK));
+                         st_mult(4, edge_value & GRAPH_EDGE_LAST_MASK));
        do {
                edge_value = get_be32(parent_data_ptr);
                pptr = insert_parent_or_die(r, g,
@@ -969,7 +988,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));
@@ -1446,24 +1465,52 @@ static void close_reachable(struct write_commit_graph_context *ctx)
        stop_progress(&ctx->progress);
 }
 
-static void compute_topological_levels(struct write_commit_graph_context *ctx)
+struct compute_generation_info {
+       struct repository *r;
+       struct packed_commit_list *commits;
+       struct progress *progress;
+       int progress_cnt;
+
+       timestamp_t (*get_generation)(struct commit *c, void *data);
+       void (*set_generation)(struct commit *c, timestamp_t gen, void *data);
+       void *data;
+};
+
+static timestamp_t compute_generation_from_max(struct commit *c,
+                                              timestamp_t max_gen,
+                                              int generation_version)
+{
+       switch (generation_version) {
+       case 1: /* topological levels */
+               if (max_gen > GENERATION_NUMBER_V1_MAX - 1)
+                       max_gen = GENERATION_NUMBER_V1_MAX - 1;
+               return max_gen + 1;
+
+       case 2: /* corrected commit date */
+               if (c->date && c->date > max_gen)
+                       max_gen = c->date - 1;
+               return max_gen + 1;
+
+       default:
+               BUG("attempting unimplemented version");
+       }
+}
+
+static void compute_reachable_generation_numbers(
+                       struct compute_generation_info *info,
+                       int generation_version)
 {
        int i;
        struct commit_list *list = NULL;
 
-       if (ctx->report_progress)
-               ctx->progress = start_delayed_progress(
-                                       _("Computing commit graph topological levels"),
-                                       ctx->commits.nr);
-       for (i = 0; i < ctx->commits.nr; i++) {
-               struct commit *c = ctx->commits.list[i];
-               uint32_t level;
+       for (i = 0; i < info->commits->nr; i++) {
+               struct commit *c = info->commits->list[i];
+               timestamp_t gen;
+               repo_parse_commit(info->r, c);
+               gen = info->get_generation(c, info->data);
+               display_progress(info->progress, info->progress_cnt + 1);
 
-               repo_parse_commit(ctx->r, c);
-               level = *topo_level_slab_at(ctx->topo_levels, c);
-
-               display_progress(ctx->progress, i + 1);
-               if (level != GENERATION_NUMBER_ZERO)
+               if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY)
                        continue;
 
                commit_list_insert(c, &list);
@@ -1471,41 +1518,91 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)
                        struct commit *current = list->item;
                        struct commit_list *parent;
                        int all_parents_computed = 1;
-                       uint32_t max_level = 0;
+                       uint32_t max_gen = 0;
 
                        for (parent = current->parents; parent; parent = parent->next) {
-                               repo_parse_commit(ctx->r, parent->item);
-                               level = *topo_level_slab_at(ctx->topo_levels, parent->item);
+                               repo_parse_commit(info->r, parent->item);
+                               gen = info->get_generation(parent->item, info->data);
 
-                               if (level == GENERATION_NUMBER_ZERO) {
+                               if (gen == GENERATION_NUMBER_ZERO) {
                                        all_parents_computed = 0;
                                        commit_list_insert(parent->item, &list);
                                        break;
                                }
 
-                               if (level > max_level)
-                                       max_level = level;
+                               if (gen > max_gen)
+                                       max_gen = gen;
                        }
 
                        if (all_parents_computed) {
                                pop_commit(&list);
-
-                               if (max_level > GENERATION_NUMBER_V1_MAX - 1)
-                                       max_level = GENERATION_NUMBER_V1_MAX - 1;
-                               *topo_level_slab_at(ctx->topo_levels, current) = max_level + 1;
+                               gen = compute_generation_from_max(
+                                               current, max_gen,
+                                               generation_version);
+                               info->set_generation(current, gen, info->data);
                        }
                }
        }
+}
+
+static timestamp_t get_topo_level(struct commit *c, void *data)
+{
+       struct write_commit_graph_context *ctx = data;
+       return *topo_level_slab_at(ctx->topo_levels, c);
+}
+
+static void set_topo_level(struct commit *c, timestamp_t t, void *data)
+{
+       struct write_commit_graph_context *ctx = data;
+       *topo_level_slab_at(ctx->topo_levels, c) = (uint32_t)t;
+}
+
+static void compute_topological_levels(struct write_commit_graph_context *ctx)
+{
+       struct compute_generation_info info = {
+               .r = ctx->r,
+               .commits = &ctx->commits,
+               .get_generation = get_topo_level,
+               .set_generation = set_topo_level,
+               .data = ctx,
+       };
+
+       if (ctx->report_progress)
+               info.progress = ctx->progress
+                             = start_delayed_progress(
+                                       _("Computing commit graph topological levels"),
+                                       ctx->commits.nr);
+
+       compute_reachable_generation_numbers(&info, 1);
+
        stop_progress(&ctx->progress);
 }
 
+static timestamp_t get_generation_from_graph_data(struct commit *c, void *data)
+{
+       return commit_graph_data_at(c)->generation;
+}
+
+static void set_generation_v2(struct commit *c, timestamp_t t, void *data)
+{
+       struct commit_graph_data *g = commit_graph_data_at(c);
+       g->generation = t;
+}
+
 static void compute_generation_numbers(struct write_commit_graph_context *ctx)
 {
        int i;
-       struct commit_list *list = NULL;
+       struct compute_generation_info info = {
+               .r = ctx->r,
+               .commits = &ctx->commits,
+               .get_generation = get_generation_from_graph_data,
+               .set_generation = set_generation_v2,
+               .data = ctx,
+       };
 
        if (ctx->report_progress)
-               ctx->progress = start_delayed_progress(
+               info.progress = ctx->progress
+                             = start_delayed_progress(
                                        _("Computing commit graph generation numbers"),
                                        ctx->commits.nr);
 
@@ -1517,47 +1614,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                }
        }
 
-       for (i = 0; i < ctx->commits.nr; i++) {
-               struct commit *c = ctx->commits.list[i];
-               timestamp_t corrected_commit_date;
-
-               repo_parse_commit(ctx->r, c);
-               corrected_commit_date = commit_graph_data_at(c)->generation;
-
-               display_progress(ctx->progress, i + 1);
-               if (corrected_commit_date != GENERATION_NUMBER_ZERO)
-                       continue;
-
-               commit_list_insert(c, &list);
-               while (list) {
-                       struct commit *current = list->item;
-                       struct commit_list *parent;
-                       int all_parents_computed = 1;
-                       timestamp_t max_corrected_commit_date = 0;
-
-                       for (parent = current->parents; parent; parent = parent->next) {
-                               repo_parse_commit(ctx->r, parent->item);
-                               corrected_commit_date = commit_graph_data_at(parent->item)->generation;
-
-                               if (corrected_commit_date == GENERATION_NUMBER_ZERO) {
-                                       all_parents_computed = 0;
-                                       commit_list_insert(parent->item, &list);
-                                       break;
-                               }
-
-                               if (corrected_commit_date > max_corrected_commit_date)
-                                       max_corrected_commit_date = corrected_commit_date;
-                       }
-
-                       if (all_parents_computed) {
-                               pop_commit(&list);
-
-                               if (current->date && current->date > max_corrected_commit_date)
-                                       max_corrected_commit_date = current->date - 1;
-                               commit_graph_data_at(current)->generation = max_corrected_commit_date + 1;
-                       }
-               }
-       }
+       compute_reachable_generation_numbers(&info, 2);
 
        for (i = 0; i < ctx->commits.nr; i++) {
                struct commit *c = ctx->commits.list[i];
@@ -1568,6 +1625,35 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
        stop_progress(&ctx->progress);
 }
 
+static void set_generation_in_graph_data(struct commit *c, timestamp_t t,
+                                        void *data)
+{
+       commit_graph_data_at(c)->generation = t;
+}
+
+/*
+ * After this method, all commits reachable from those in the given
+ * list will have non-zero, non-infinite generation numbers.
+ */
+void ensure_generations_valid(struct repository *r,
+                             struct commit **commits, size_t nr)
+{
+       int generation_version = get_configured_generation_version(r);
+       struct packed_commit_list list = {
+               .list = commits,
+               .alloc = nr,
+               .nr = nr,
+       };
+       struct compute_generation_info info = {
+               .r = r,
+               .commits = &list,
+               .get_generation = get_generation_from_graph_data,
+               .set_generation = set_generation_in_graph_data,
+       };
+
+       compute_reachable_generation_numbers(&info, generation_version);
+}
+
 static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)
 {
        trace2_data_intmax("commit-graph", ctx->r, "filter-computed",
@@ -1882,35 +1968,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);
@@ -1928,7 +2014,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);
@@ -2034,11 +2120,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;
 
@@ -2096,6 +2187,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++) {
@@ -2360,13 +2456,13 @@ int write_commit_graph(struct object_directory *odb,
                        replace = ctx->opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;
        }
 
-       ctx->approx_nr_objects = approximate_object_count();
+       ctx->approx_nr_objects = repo_approximate_object_count(the_repository);
 
        if (ctx->append && ctx->r->objects->commit_graph) {
                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);
                }
        }
@@ -2464,26 +2560,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)
@@ -2497,7 +2587,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"),
@@ -2534,22 +2624,18 @@ 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));
-               if (parse_commit_internal(odb_commit, 0, 0)) {
+               if (repo_parse_commit_internal(r, odb_commit, 0, 0)) {
                        graph_report(_("failed to parse commit %s from object database for commit-graph"),
                                     oid_to_hex(&cur_oid));
                        continue;
@@ -2581,7 +2667,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;
 
@@ -2593,16 +2679,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;
 
                /*
@@ -2627,12 +2709,43 @@ 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));
+
+       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_VERIFY_SHALLOW) && g->base_graph)
-               local_error |= verify_commit_graph(r, g->base_graph, flags);
+       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;
 }
index 37faee6b66d59c693dc9ee829dbd5ad61654fe3c..5e534f0fcc8d131a6e759ed1658b0e0984123a6e 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef COMMIT_GRAPH_H
 #define COMMIT_GRAPH_H
 
-#include "git-compat-util.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oidset.h"
 
 #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
@@ -190,4 +189,12 @@ struct commit_graph_data {
  */
 timestamp_t commit_graph_generation(const struct commit *);
 uint32_t commit_graph_position(const struct commit *);
+
+/*
+ * After this method, all commits reachable from those in the given
+ * list will have non-zero, non-infinite generation numbers.
+ */
+void ensure_generations_valid(struct repository *r,
+                             struct commit **commits, size_t nr);
+
 #endif
index 2e33c599a82c81127b9a24547d0834e6c7a55bcf..4b7c233fd468f9ad2a60abf5b9202f5c4fbad3c4 100644 (file)
@@ -1,13 +1,15 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "commit.h"
 #include "commit-graph.h"
 #include "decorate.h"
+#include "hex.h"
 #include "prio-queue.h"
 #include "tree.h"
 #include "ref-filter.h"
 #include "revision.h"
 #include "tag.h"
 #include "commit-reach.h"
+#include "ewah/ewok.h"
 
 /* Remember to update object flag allocation in object.h */
 #define PARENT1                (1u<<16)
@@ -162,7 +164,8 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 
                for (j = ret; j; j = j->next) {
                        struct commit_list *bases;
-                       bases = get_merge_bases(i->item, j->item);
+                       bases = repo_get_merge_bases(the_repository, i->item,
+                                                    j->item);
                        if (!new_commits)
                                new_commits = bases;
                        else
@@ -447,7 +450,7 @@ int repo_is_descendant_of(struct repository *r,
        if (!with_commit)
                return 1;
 
-       if (generation_numbers_enabled(the_repository)) {
+       if (generation_numbers_enabled(r)) {
                struct commit_list *from_list = NULL;
                int result;
                commit_list_insert(commit, &from_list);
@@ -584,7 +587,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
                return 0;
        new_commit = (struct commit *) o;
 
-       if (parse_commit(new_commit) < 0)
+       if (repo_parse_commit(the_repository, new_commit) < 0)
                return 0;
 
        commit_list_insert(old_commit, &old_commit_list);
@@ -748,7 +751,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
                }
 
                list[nr_commits] = (struct commit *)from_one;
-               if (parse_commit(list[nr_commits]) ||
+               if (repo_parse_commit(the_repository, list[nr_commits]) ||
                    commit_graph_generation(list[nr_commits]) < min_generation) {
                        result = 0;
                        goto cleanup;
@@ -783,7 +786,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
                                if (!(parent->item->object.flags & assign_flag)) {
                                        parent->item->object.flags |= assign_flag;
 
-                                       if (parse_commit(parent->item) ||
+                                       if (repo_parse_commit(the_repository, parent->item) ||
                                            parent->item->date < min_commit_date ||
                                            commit_graph_generation(parent->item) < min_generation)
                                                continue;
@@ -807,8 +810,12 @@ cleanup:
        clear_commit_marks_many(nr_commits, list, RESULT | assign_flag);
        free(list);
 
-       for (i = 0; i < from->nr; i++)
-               from->objects[i].item->flags &= ~assign_flag;
+       for (i = 0; i < from->nr; i++) {
+               struct object *from_one = from->objects[i].item;
+
+               if (from_one)
+                       from_one->flags &= ~assign_flag;
+       }
 
        return result;
 }
@@ -825,7 +832,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
        while (from_iter) {
                add_object_array(&from_iter->item->object, NULL, &from_objs);
 
-               if (!parse_commit(from_iter->item)) {
+               if (!repo_parse_commit(the_repository, from_iter->item)) {
                        timestamp_t generation;
                        if (from_iter->item->date < min_commit_date)
                                min_commit_date = from_iter->item->date;
@@ -839,7 +846,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
        }
 
        while (to_iter) {
-               if (!parse_commit(to_iter->item)) {
+               if (!repo_parse_commit(the_repository, to_iter->item)) {
                        timestamp_t generation;
                        if (to_iter->item->date < min_commit_date)
                                min_commit_date = to_iter->item->date;
@@ -889,7 +896,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
                timestamp_t generation;
                struct commit *c = *item;
 
-               parse_commit(c);
+               repo_parse_commit(the_repository, c);
                generation = commit_graph_generation(c);
                if (generation < min_generation)
                        min_generation = generation;
@@ -904,7 +911,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
                struct commit *c = *item;
                if (!(c->object.flags & PARENT2)) {
                        c->object.flags |= PARENT2;
-                       parse_commit(c);
+                       repo_parse_commit(the_repository, c);
 
                        prio_queue_put(&queue, *item);
                }
@@ -923,7 +930,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
                for (parents = current->parents; parents; parents = parents->next) {
                        struct commit *p = parents->item;
 
-                       parse_commit(p);
+                       repo_parse_commit(the_repository, p);
 
                        if (commit_graph_generation(p) < min_generation)
                                continue;
@@ -936,8 +943,225 @@ 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);
 
        return found_commits;
 }
+
+define_commit_slab(bit_arrays, struct bitmap *);
+static struct bit_arrays bit_arrays;
+
+static void insert_no_dup(struct prio_queue *queue, struct commit *c)
+{
+       if (c->object.flags & PARENT2)
+               return;
+       prio_queue_put(queue, c);
+       c->object.flags |= PARENT2;
+}
+
+static struct bitmap *get_bit_array(struct commit *c, int width)
+{
+       struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c);
+       if (!*bitmap)
+               *bitmap = bitmap_word_alloc(width);
+       return *bitmap;
+}
+
+static void free_bit_array(struct commit *c)
+{
+       struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c);
+       if (!*bitmap)
+               return;
+       bitmap_free(*bitmap);
+       *bitmap = NULL;
+}
+
+void ahead_behind(struct repository *r,
+                 struct commit **commits, size_t commits_nr,
+                 struct ahead_behind_count *counts, size_t counts_nr)
+{
+       struct prio_queue queue = { .compare = compare_commits_by_gen_then_commit_date };
+       size_t width = DIV_ROUND_UP(commits_nr, BITS_IN_EWORD);
+
+       if (!commits_nr || !counts_nr)
+               return;
+
+       for (size_t i = 0; i < counts_nr; i++) {
+               counts[i].ahead = 0;
+               counts[i].behind = 0;
+       }
+
+       ensure_generations_valid(r, commits, commits_nr);
+
+       init_bit_arrays(&bit_arrays);
+
+       for (size_t i = 0; i < commits_nr; i++) {
+               struct commit *c = commits[i];
+               struct bitmap *bitmap = get_bit_array(c, width);
+
+               bitmap_set(bitmap, i);
+               insert_no_dup(&queue, c);
+       }
+
+       while (queue_has_nonstale(&queue)) {
+               struct commit *c = prio_queue_get(&queue);
+               struct commit_list *p;
+               struct bitmap *bitmap_c = get_bit_array(c, width);
+
+               for (size_t i = 0; i < counts_nr; i++) {
+                       int reach_from_tip = !!bitmap_get(bitmap_c, counts[i].tip_index);
+                       int reach_from_base = !!bitmap_get(bitmap_c, counts[i].base_index);
+
+                       if (reach_from_tip ^ reach_from_base) {
+                               if (reach_from_base)
+                                       counts[i].behind++;
+                               else
+                                       counts[i].ahead++;
+                       }
+               }
+
+               for (p = c->parents; p; p = p->next) {
+                       struct bitmap *bitmap_p;
+
+                       repo_parse_commit(r, p->item);
+
+                       bitmap_p = get_bit_array(p->item, width);
+                       bitmap_or(bitmap_p, bitmap_c);
+
+                       /*
+                        * If this parent is reachable from every starting
+                        * commit, then none of its ancestors can contribute
+                        * to the ahead/behind count. Mark it as STALE, so
+                        * we can stop the walk when every commit in the
+                        * queue is STALE.
+                        */
+                       if (bitmap_popcount(bitmap_p) == commits_nr)
+                               p->item->object.flags |= STALE;
+
+                       insert_no_dup(&queue, p->item);
+               }
+
+               free_bit_array(c);
+       }
+
+       /* STALE is used here, PARENT2 is used by insert_no_dup(). */
+       repo_clear_commit_marks(r, PARENT2 | STALE);
+       clear_bit_arrays(&bit_arrays);
+       clear_prio_queue(&queue);
+}
+
+struct commit_and_index {
+       struct commit *commit;
+       unsigned int index;
+       timestamp_t generation;
+};
+
+static int compare_commit_and_index_by_generation(const void *va, const void *vb)
+{
+       const struct commit_and_index *a = (const struct commit_and_index *)va;
+       const struct commit_and_index *b = (const struct commit_and_index *)vb;
+
+       if (a->generation > b->generation)
+               return 1;
+       if (a->generation < b->generation)
+               return -1;
+       return 0;
+}
+
+void tips_reachable_from_bases(struct repository *r,
+                              struct commit_list *bases,
+                              struct commit **tips, size_t tips_nr,
+                              int mark)
+{
+       struct commit_and_index *commits;
+       size_t min_generation_index = 0;
+       timestamp_t min_generation;
+       struct commit_list *stack = NULL;
+
+       if (!bases || !tips || !tips_nr)
+               return;
+
+       /*
+        * Do a depth-first search starting at 'bases' to search for the
+        * tips. Stop at the lowest (un-found) generation number. When
+        * finding the lowest commit, increase the minimum generation
+        * number to the next lowest (un-found) generation number.
+        */
+
+       CALLOC_ARRAY(commits, tips_nr);
+
+       for (size_t i = 0; i < tips_nr; i++) {
+               commits[i].commit = tips[i];
+               commits[i].index = i;
+               commits[i].generation = commit_graph_generation(tips[i]);
+       }
+
+       /* Sort with generation number ascending. */
+       QSORT(commits, tips_nr, compare_commit_and_index_by_generation);
+       min_generation = commits[0].generation;
+
+       while (bases) {
+               repo_parse_commit(r, bases->item);
+               commit_list_insert(bases->item, &stack);
+               bases = bases->next;
+       }
+
+       while (stack) {
+               int explored_all_parents = 1;
+               struct commit_list *p;
+               struct commit *c = stack->item;
+               timestamp_t c_gen = commit_graph_generation(c);
+
+               /* Does it match any of our tips? */
+               for (size_t j = min_generation_index; j < tips_nr; j++) {
+                       if (c_gen < commits[j].generation)
+                               break;
+
+                       if (commits[j].commit == c) {
+                               tips[commits[j].index]->object.flags |= mark;
+
+                               if (j == min_generation_index) {
+                                       unsigned int k = j + 1;
+                                       while (k < tips_nr &&
+                                              (tips[commits[k].index]->object.flags & mark))
+                                               k++;
+
+                                       /* Terminate early if all found. */
+                                       if (k >= tips_nr)
+                                               goto done;
+
+                                       min_generation_index = k;
+                                       min_generation = commits[k].generation;
+                               }
+                       }
+               }
+
+               for (p = c->parents; p; p = p->next) {
+                       repo_parse_commit(r, p->item);
+
+                       /* Have we already explored this parent? */
+                       if (p->item->object.flags & SEEN)
+                               continue;
+
+                       /* Is it below the current minimum generation? */
+                       if (commit_graph_generation(p->item) < min_generation)
+                               continue;
+
+                       /* Ok, we will explore from here on. */
+                       p->item->object.flags |= SEEN;
+                       explored_all_parents = 0;
+                       commit_list_insert(p->item, &stack);
+                       break;
+               }
+
+               if (explored_all_parents)
+                       pop_commit(&stack);
+       }
+
+done:
+       free(commits);
+       repo_clear_commit_marks(r, SEEN);
+}
index 148b56fea50629607d2f0dd196cbd4dec08fdcfd..35c4da4948122a6caea3a1757484b487db16b0fd 100644 (file)
@@ -19,11 +19,6 @@ struct commit_list *repo_get_merge_bases_many(struct repository *r,
 struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
                                                    struct commit *one, int n,
                                                    struct commit **twos);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define get_merge_bases(r1, r2)           repo_get_merge_bases(the_repository, r1, r2)
-#define get_merge_bases_many(one, n, two) repo_get_merge_bases_many(the_repository, one, n, two)
-#define get_merge_bases_many_dirty(one, n, twos) repo_get_merge_bases_many_dirty(the_repository, one, n, twos)
-#endif
 
 struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 
@@ -36,10 +31,6 @@ int repo_in_merge_bases(struct repository *r,
 int repo_in_merge_bases_many(struct repository *r,
                             struct commit *commit,
                             int nr_reference, struct commit **reference);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define in_merge_bases(c1, c2) repo_in_merge_bases(the_repository, c1, c2)
-#define in_merge_bases_many(c1, n, cs) repo_in_merge_bases_many(the_repository, c1, n, cs)
-#endif
 
 /*
  * Takes a list of commits and returns a new list where those
@@ -104,4 +95,44 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
                                         struct commit **to, int nr_to,
                                         unsigned int reachable_flag);
 
+struct ahead_behind_count {
+       /**
+        * As input, the *_index members indicate which positions in
+        * the 'tips' array correspond to the tip and base of this
+        * comparison.
+        */
+       size_t tip_index;
+       size_t base_index;
+
+       /**
+        * These values store the computed counts for each side of the
+        * symmetric difference:
+        *
+        * 'ahead' stores the number of commits reachable from the tip
+        * and not reachable from the base.
+        *
+        * 'behind' stores the number of commits reachable from the base
+        * and not reachable from the tip.
+        */
+       unsigned int ahead;
+       unsigned int behind;
+};
+
+/*
+ * Given an array of commits and an array of ahead_behind_count pairs,
+ * compute the ahead/behind counts for each pair.
+ */
+void ahead_behind(struct repository *r,
+                 struct commit **commits, size_t commits_nr,
+                 struct ahead_behind_count *counts, size_t counts_nr);
+
+/*
+ * For all tip commits, add 'mark' to their flags if and only if they
+ * are reachable from one of the commits in 'bases'.
+ */
+void tips_reachable_from_bases(struct repository *r,
+                              struct commit_list *bases,
+                              struct commit **tips, size_t tips_nr,
+                              int mark);
+
 #endif
index 557738df271c7dd78c5ddcc65d6fe6e47c665758..4a414ee905d5de4498d1fcca2da53e7c6a07b50e 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef COMMIT_SLAB_IMPL_H
 #define COMMIT_SLAB_IMPL_H
 
-#include "git-compat-util.h"
-
 #define implement_static_commit_slab(slabname, elemtype) \
        implement_commit_slab(slabname, elemtype, MAYBE_UNUSED static)
 
index e433c33bb01fa6e3688a0b163c44d62f204d62d0..b3223478bc2a3ac98751e41ba133a41d3ba34bc0 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1,9 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "tag.h"
 #include "commit.h"
 #include "commit-graph.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "pkt-line.h"
 #include "utf8.h"
 #include "diff.h"
@@ -20,7 +24,9 @@
 #include "refs.h"
 #include "commit-reach.h"
 #include "run-command.h"
+#include "setup.h"
 #include "shallow.h"
+#include "tree.h"
 #include "hook.h"
 
 static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -80,10 +86,10 @@ struct commit *lookup_commit_reference_by_name(const char *name)
        struct object_id oid;
        struct commit *commit;
 
-       if (get_oid_committish(name, &oid))
+       if (repo_get_oid_committish(the_repository, name, &oid))
                return NULL;
        commit = lookup_commit_reference(the_repository, &oid);
-       if (parse_commit(commit))
+       if (repo_parse_commit(the_repository, commit))
                return NULL;
        return commit;
 }
@@ -91,6 +97,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
 static timestamp_t parse_commit_date(const char *buf, const char *tail)
 {
        const char *dateptr;
+       const char *eol;
 
        if (buf + 6 >= tail)
                return 0;
@@ -102,16 +109,56 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail)
                return 0;
        if (memcmp(buf, "committer", 9))
                return 0;
-       while (buf < tail && *buf++ != '>')
-               /* nada */;
-       if (buf >= tail)
+
+       /*
+        * Jump to end-of-line so that we can walk backwards to find the
+        * end-of-email ">". This is more forgiving of malformed cases
+        * because unexpected characters tend to be in the name and email
+        * fields.
+        */
+       eol = memchr(buf, '\n', tail - buf);
+       if (!eol)
                return 0;
-       dateptr = buf;
-       while (buf < tail && *buf++ != '\n')
-               /* nada */;
-       if (buf >= tail)
+       dateptr = eol;
+       while (dateptr > buf && dateptr[-1] != '>')
+               dateptr--;
+       if (dateptr == buf)
                return 0;
-       /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
+
+       /*
+        * Trim leading whitespace, but make sure we have at least one
+        * non-whitespace character, as parse_timestamp() will otherwise walk
+        * right past the newline we found in "eol" when skipping whitespace
+        * itself.
+        *
+        * In theory it would be sufficient to allow any character not matched
+        * by isspace(), but there's a catch: our isspace() does not
+        * necessarily match the behavior of parse_timestamp(), as the latter
+        * is implemented by system routines which match more exotic control
+        * codes, or even locale-dependent sequences.
+        *
+        * Since we expect the timestamp to be a number, we can check for that.
+        * Anything else (e.g., a non-numeric token like "foo") would just
+        * cause parse_timestamp() to return 0 anyway.
+        */
+       while (dateptr < eol && isspace(*dateptr))
+               dateptr++;
+       if (!isdigit(*dateptr) && *dateptr != '-')
+               return 0;
+
+       /*
+        * We know there is at least one digit (or dash), so we'll begin
+        * parsing there and stop at worst case at eol.
+        *
+        * Note that we may feed parse_timestamp() extra characters here if the
+        * commit is malformed, and it will parse as far as it can. For
+        * example, "123foo456" would return "123". That might be questionable
+        * (versus returning "0"), but it would help in a hypothetical case
+        * like "123456+0100", where the whitespace from the timezone is
+        * missing. Since such syntactic errors may be baked into history and
+        * hard to correct now, let's err on trying to make our best guess
+        * here, rather than insist on perfect syntax.
+        */
        return parse_timestamp(dateptr, NULL, 10);
 }
 
@@ -382,7 +429,7 @@ struct tree *repo_get_commit_tree(struct repository *r,
 
 struct object_id *get_commit_tree_oid(const struct commit *commit)
 {
-       struct tree *tree = get_commit_tree(commit);
+       struct tree *tree = repo_get_commit_tree(the_repository, commit);
        return tree ? &tree->object.oid : NULL;
 }
 
@@ -469,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)
@@ -555,7 +602,7 @@ int repo_parse_commit_gently(struct repository *r,
 
 void parse_commit_or_die(struct commit *item)
 {
-       if (parse_commit(item))
+       if (repo_parse_commit(the_repository, item))
                die("unable to parse commit %s",
                    item ? oid_to_hex(&item->object.oid) : "(null)");
 }
@@ -688,7 +735,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
 
        while (parents) {
                struct commit *commit = parents->item;
-               if (!parse_commit(commit) && !(commit->object.flags & mark)) {
+               if (!repo_parse_commit(the_repository, commit) && !(commit->object.flags & mark)) {
                        commit->object.flags |= mark;
                        commit_list_insert_by_date(commit, list);
                }
@@ -762,7 +809,8 @@ define_commit_slab(author_date_slab, timestamp_t);
 void record_author_date(struct author_date_slab *author_date,
                        struct commit *commit)
 {
-       const char *buffer = get_commit_buffer(commit, NULL);
+       const char *buffer = repo_get_commit_buffer(the_repository, commit,
+                                                   NULL);
        struct ident_split ident;
        const char *ident_line;
        size_t ident_len;
@@ -782,7 +830,7 @@ void record_author_date(struct author_date_slab *author_date,
        *(author_date_slab_at(author_date, commit)) = date;
 
 fail_exit:
-       unuse_commit_buffer(commit, buffer);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
 }
 
 int compare_commits_by_author_date(const void *a_, const void *b_,
@@ -801,7 +849,8 @@ int compare_commits_by_author_date(const void *a_, const void *b_,
        return 0;
 }
 
-int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_,
+                                           void *unused UNUSED)
 {
        const struct commit *a = a_, *b = b_;
        const timestamp_t generation_a = commit_graph_generation(a),
@@ -821,7 +870,8 @@ int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void
        return 0;
 }
 
-int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
+int compare_commits_by_commit_date(const void *a_, const void *b_,
+                                  void *unused UNUSED)
 {
        const struct commit *a = a_, *b = b_;
        /* newer commits with larger date first */
@@ -963,7 +1013,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
        commit = lookup_commit(the_repository, oid);
        if (!commit ||
            (commit->object.flags & TMP_MARK) ||
-           parse_commit(commit))
+           repo_parse_commit(the_repository, commit))
                return;
 
        ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
@@ -995,7 +1045,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
        struct commit *ret = NULL;
        char *full_refname;
 
-       switch (dwim_ref(refname, strlen(refname), &oid, &full_refname, 0)) {
+       switch (repo_dwim_ref(the_repository, refname, strlen(refname), &oid,
+                             &full_refname, 0)) {
        case 0:
                die("No such ref: '%s'", refname);
        case 1:
@@ -1014,7 +1065,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
        for (i = 0; i < revs.nr; i++)
                revs.commit[i]->object.flags &= ~TMP_MARK;
 
-       bases = get_merge_bases_many(commit, revs.nr, revs.commit);
+       bases = repo_get_merge_bases_many(the_repository, commit, revs.nr,
+                                         revs.commit);
 
        /*
         * There should be one and only one merge base, when we found
@@ -1095,10 +1147,11 @@ int parse_signed_commit(const struct commit *commit,
                        const struct git_hash_algo *algop)
 {
        unsigned long size;
-       const char *buffer = get_commit_buffer(commit, &size);
+       const char *buffer = repo_get_commit_buffer(the_repository, commit,
+                                                   &size);
        int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
 
-       unuse_commit_buffer(commit, buffer);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
        return ret;
 }
 
@@ -1209,7 +1262,8 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
        desc = merge_remote_util(parent);
        if (!desc || !desc->obj)
                return;
-       buf = read_object_file(&desc->obj->oid, &type, &size);
+       buf = repo_read_object_file(the_repository, &desc->obj->oid, &type,
+                                   &size);
        if (!buf || type != OBJ_TAG)
                goto free_return;
        if (!parse_signature(buf, size, &payload, &signature))
@@ -1271,7 +1325,8 @@ void verify_merge_signature(struct commit *commit, int verbosity,
 
        ret = check_commit_signature(commit, &signature_check);
 
-       find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
+       repo_find_unique_abbrev_r(the_repository, hex, &commit->object.oid,
+                                 DEFAULT_ABBREV);
        switch (signature_check.result) {
        case 'G':
                if (ret || (check_trust && signature_check.trust_level < TRUST_MARGINAL))
@@ -1316,9 +1371,10 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
 {
        struct commit_extra_header *extra = NULL;
        unsigned long size;
-       const char *buffer = get_commit_buffer(commit, &size);
+       const char *buffer = repo_get_commit_buffer(the_repository, commit,
+                                                   &size);
        extra = read_commit_extra_header_lines(buffer, size, exclude);
-       unuse_commit_buffer(commit, buffer);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
        return extra;
 }
 
@@ -1632,10 +1688,11 @@ struct commit *get_merge_parent(const char *name)
        struct object *obj;
        struct commit *commit;
        struct object_id oid;
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                return NULL;
        obj = parse_object(the_repository, &oid);
-       commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
+       commit = (struct commit *)repo_peel_to_type(the_repository, name, 0,
+                                                   obj, OBJ_COMMIT);
        if (commit && !merge_remote_util(commit))
                set_merge_remote_desc(commit, name, obj);
        return commit;
index cc2c5da7bdb8344e9dbe69ae16092fcbf004d544..28928833c544081f9c08971f7a4450e97154ebb3 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -2,13 +2,10 @@
 #define COMMIT_H
 
 #include "object.h"
-#include "tree.h"
-#include "strbuf.h"
-#include "decorate.h"
-#include "gpg-interface.h"
-#include "string-list.h"
-#include "pretty.h"
-#include "commit-slab.h"
+
+struct signature_check;
+struct strbuf;
+struct tree;
 
 #define COMMIT_NOT_FROM_GRAPH 0xFFFFFFFF
 #define GENERATION_NUMBER_INFINITY ((1ULL << 63) - 1)
@@ -109,11 +106,6 @@ static inline int repo_parse_commit_no_graph(struct repository *r,
        return repo_parse_commit_internal(r, commit, 0, 0);
 }
 
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define parse_commit_internal(item, quiet, use) repo_parse_commit_internal(the_repository, item, quiet, use)
-#define parse_commit(item) repo_parse_commit(the_repository, item)
-#endif
-
 void parse_commit_or_die(struct commit *item);
 
 struct buffer_slab;
@@ -135,27 +127,21 @@ const void *get_cached_commit_buffer(struct repository *, const struct commit *,
 /*
  * Get the commit's object contents, either from cache or by reading the object
  * from disk. The resulting memory should not be modified, and must be given
- * to unuse_commit_buffer when the caller is done.
+ * to repo_unuse_commit_buffer when the caller is done.
  */
 const void *repo_get_commit_buffer(struct repository *r,
                                   const struct commit *,
                                   unsigned long *size);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define get_commit_buffer(c, s) repo_get_commit_buffer(the_repository, c, s)
-#endif
 
 /*
  * Tell the commit subsystem that we are done with a particular commit buffer.
  * The commit and buffer should be the input and return value, respectively,
- * from an earlier call to get_commit_buffer.  The buffer may or may not be
+ * from an earlier call to repo_get_commit_buffer.  The buffer may or may not be
  * freed by this call; callers should not access the memory afterwards.
  */
 void repo_unuse_commit_buffer(struct repository *r,
                              const struct commit *,
                              const void *buffer);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define unuse_commit_buffer(c, b) repo_unuse_commit_buffer(the_repository, c, b)
-#endif
 
 /*
  * Free any cached object buffer associated with the commit.
@@ -163,7 +149,6 @@ void repo_unuse_commit_buffer(struct repository *r,
 void free_commit_buffer(struct parsed_object_pool *pool, struct commit *);
 
 struct tree *repo_get_commit_tree(struct repository *, const struct commit *);
-#define get_commit_tree(c) repo_get_commit_tree(the_repository, c)
 struct object_id *get_commit_tree_oid(const struct commit *);
 
 /*
@@ -205,17 +190,10 @@ void free_commit_list(struct commit_list *list);
 
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 
-int has_non_ascii(const char *text);
-const char *logmsg_reencode(const struct commit *commit,
-                           char **commit_encoding,
-                           const char *output_encoding);
 const char *repo_logmsg_reencode(struct repository *r,
                                 const struct commit *commit,
                                 char **commit_encoding,
                                 const char *output_encoding);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define logmsg_reencode(c, enc, out) repo_logmsg_reencode(the_repository, c, enc, out)
-#endif
 
 const char *skip_blank_lines(const char *msg);
 
index 0a22861f1ceb28547002a237e7201eb920eb9d68..033778b3c56a3557e191d3bb74592fd00497853b 100644 (file)
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "exec-cmd.h"
+#include "gettext.h"
 #include "attr.h"
+#include "repository.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "trace2.h"
 
 /*
  * Many parts of Git have subprograms communicate via pipe, expect the
index 50a32e3d8a43bc2bc45c8c8afa2c59e79518fc07..6c979c27d89ec858b849f87e64505c2554cb121b 100644 (file)
@@ -2,6 +2,8 @@
 #define COMPAT_DISK_H
 
 #include "git-compat-util.h"
+#include "abspath.h"
+#include "gettext.h"
 
 static int get_disk_info(struct strbuf *out)
 {
index b9f709e854833f67b45725e1684abe2ef06e16ca..5b1709d63f729b173d89152e37567dcb3459117a 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"
 
index 2ea08c1d4e81ecec5c6cada8f0e9fff76303fcc4..2d4e245beb18b8f3573ea33526274d3f8f45b675 100644 (file)
@@ -1,8 +1,9 @@
-#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"
 
 /*
  * Every minute wake up and test our health.
index d67b0ee50d351682f2a9e5e80c3164fa601f65e6..6f3a95410cc1002a08b4af63bc9fff0d1e1e75ea 100644 (file)
@@ -1,7 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #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 e08c505c148933ed830ae2071198999827d84d14..8928fa93ce223968ab59279ddac50a3dd2b15239 100644 (file)
@@ -1,5 +1,7 @@
+#include "git-compat-util.h"
 #include "config.h"
 #include "fsmonitor-ipc.h"
+#include "path.h"
 
 const char *fsmonitor_ipc__get_path(struct repository *r) {
        static char *ret;
index 97a55a6f0a42d8c0ba8b1d14e077e60e7fdd55df..36c7e13281c675cba46d7a219f31f238f361c17c 100644 (file)
 #endif
 #endif
 
-#include "cache.h"
-#include "fsmonitor.h"
+#include "git-compat-util.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
 {
index 03df8d951b871f80da8b66dda8582df2eb4b9d91..a361a7db20edbf406219922acebf2291f315b22c 100644 (file)
@@ -1,8 +1,10 @@
-#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"
+#include "trace2.h"
 
 /*
  * The documentation of ReadDirectoryChangesW() states that the maximum
index ce5a8febe09480467a0645d260703b69f6cd3e8f..049f97eaaf249a0206c934d8b7ae1493115246d4 100644 (file)
@@ -1,5 +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 0d95bbb416fb66f2144a96e7d8add000cd253c6c..c8a3e9dcdbb655eab0fbea2d42c1973ee67e16f7 100644 (file)
@@ -1,6 +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.
index 6abbc7af3ab53cd4911edf93d91ebf18e2c5c152..a38259063517144690122454970f399ae504708e 100644 (file)
@@ -1,5 +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..b6f67444944b5ff60ed3823dc64fc10d36f2a778 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"
 
index bc2f9382a17f8f63a783680770a46358964e8f81..4bb2d66227bd5e0197855416957c1499de8c5565 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 
 #include "strbuf.h"
 #include "strvec.h"
index e433740381be9cad8cd6c7453508931684832209..ec5280da160135170e2d778cfcb19cea1752c211 100644 (file)
@@ -6,10 +6,16 @@
 #include <wchar.h>
 #include "../strbuf.h"
 #include "../run-command.h"
-#include "../cache.h"
+#include "../abspath.h"
+#include "../alloc.h"
 #include "win32/lazyload.h"
 #include "../config.h"
+#include "../environment.h"
+#include "../trace2.h"
+#include "../symlinks.h"
+#include "../wrapper.h"
 #include "dir.h"
+#include "gettext.h"
 #define SECURITY_WIN32
 #include <sspi.h>
 
@@ -237,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"))
@@ -1340,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 978cac4ec91e6bb2f81539d85422bb37e4941a51..484e6d4c716ef6b6c3e5b24ff5a1879db3039d5d 100644 (file)
@@ -1,4 +1,5 @@
 #include "../git-compat-util.h"
+#include "../wrapper.h"
 
 ssize_t git_pread(int fd, void *buf, size_t count, off_t offset)
 {
index cce1d57a46471c9465d6a55c176a063fdfef96eb..0bd5c24250a4fb717f61db6e03e40326ca1fad07 100644 (file)
@@ -5,8 +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 1b9d359ab68185036c40a40bb2a44b8e5fbfb913..e5e1dda8ccdb60320a05b064479595eb4eb4997c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "simple-ipc.h"
 #include "strbuf.h"
 #include "pkt-line.h"
index 28a79289d4fd0a9d4e185cd5c9d8b19afdde70e7..b2f4f22ce44f51f6f8f18e0d7ca6a2ed22de183b 100644 (file)
@@ -1,8 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
 #include "simple-ipc.h"
 #include "strbuf.h"
 #include "pkt-line.h"
 #include "thread-utils.h"
+#include "trace2.h"
 #include "unix-socket.h"
 #include "unix-stream-server.h"
 
index 20ea7b65e0ba6311b22678fba5201e4a7ebeb8ce..8bfe51248e552e6915acec34abea31a3d3dc279e 100644 (file)
@@ -1,8 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "gettext.h"
 #include "simple-ipc.h"
 #include "strbuf.h"
 #include "pkt-line.h"
 #include "thread-utils.h"
+#include "trace.h"
+#include "trace2.h"
 #include "accctrl.h"
 #include "aclapi.h"
 
index ea490a7ced431a798629ca86ac904052d99f839a..83d95e8656301d29b287801d74bc4dc42af52683 100644 (file)
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "compat/terminal.h"
+#include "gettext.h"
 #include "sigchain.h"
 #include "strbuf.h"
 #include "run-command.h"
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 a53fd924340f7d6da04e5197363fe831b9d19bf3..3ef0936f6ff9711caed8c22c8aebd92eb4be6e30 100644 (file)
@@ -1,8 +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 aa2888d301a35f9ccd6d92aaae4ee177926f0424..3846a37be971c92153eb1ceeb65c6e612c8e173c 100644 (file)
--- a/config.c
+++ b/config.c
@@ -5,24 +5,40 @@
  * Copyright (C) Johannes Schindelin, 2005
  *
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
 #include "date.h"
 #include "branch.h"
 #include "config.h"
+#include "convert.h"
 #include "environment.h"
+#include "gettext.h"
+#include "ident.h"
 #include "repository.h"
 #include "lockfile.h"
+#include "mailmap.h"
 #include "exec-cmd.h"
 #include "strbuf.h"
 #include "quote.h"
 #include "hashmap.h"
 #include "string-list.h"
-#include "object-store.h"
+#include "object-name.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 "write-or-die.h"
 
 struct config_source {
        struct config_source *prev;
@@ -49,34 +65,7 @@ struct config_source {
        int (*do_ungetc)(int c, struct config_source *conf);
        long (*do_ftell)(struct config_source *c);
 };
-
-/*
- * These variables record the "current" config source, which
- * can be accessed by parsing callbacks.
- *
- * The "cf" variable will be non-NULL only when we are actually parsing a real
- * config source (file, blob, cmdline, etc).
- *
- * The "current_config_kvi" variable will be non-NULL only when we are feeding
- * cached config from a configset into a callback.
- *
- * They should generally never 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).
- */
-static struct config_source *cf;
-static struct key_value_info *current_config_kvi;
-
-/*
- * Similar to the variables above, this gives access to the "scope" of the
- * current value (repo, global, etc). For cached values, it can be found via
- * the current_config_kvi as above. During parsing, the current value can be
- * found in this variable. It's not part of "cf" because it transcends a single
- * file (i.e., a file included from .git/config is still in "repo" scope).
- */
-static enum config_scope current_parsing_scope;
+#define CONFIG_SOURCE_INIT { 0 }
 
 static int pack_compression_seen;
 static int zlib_compression_seen;
@@ -139,6 +128,7 @@ struct config_include_data {
        void *data;
        const struct config_options *opts;
        struct git_config_source *config_source;
+       struct repository *repo;
 
        /*
         * All remote URLs discovered when reading all config files.
@@ -147,7 +137,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_(
@@ -156,7 +147,9 @@ static const char include_depth_advice[] = N_(
 "from\n"
 "      %s\n"
 "This might be due to circular includes.");
-static int handle_path_include(const char *path, struct config_include_data *inc)
+static int handle_path_include(const struct key_value_info *kvi,
+                              const char *path,
+                              struct config_include_data *inc)
 {
        int ret = 0;
        struct strbuf buf = STRBUF_INIT;
@@ -177,14 +170,14 @@ static int handle_path_include(const char *path, struct config_include_data *inc
        if (!is_absolute_path(path)) {
                char *slash;
 
-               if (!cf || !cf->path) {
+               if (!kvi || !kvi->path) {
                        ret = error(_("relative config includes must come from files"));
                        goto cleanup;
                }
 
-               slash = find_last_dir_sep(cf->path);
+               slash = find_last_dir_sep(kvi->path);
                if (slash)
-                       strbuf_add(&buf, cf->path, slash - cf->path + 1);
+                       strbuf_add(&buf, kvi->path, slash - kvi->path + 1);
                strbuf_addstr(&buf, path);
                path = buf.buf;
        }
@@ -192,10 +185,11 @@ static int handle_path_include(const char *path, struct config_include_data *inc
        if (!access_or_die(path, R_OK, 0)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
-                           !cf ? "<unknown>" :
-                           cf->name ? cf->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:
@@ -210,7 +204,8 @@ static void add_trailing_starstar_for_dir(struct strbuf *pat)
                strbuf_addstr(pat, "**");
 }
 
-static int prepare_include_condition_pattern(struct strbuf *pat)
+static int prepare_include_condition_pattern(const struct key_value_info *kvi,
+                                            struct strbuf *pat)
 {
        struct strbuf path = STRBUF_INIT;
        char *expanded;
@@ -226,11 +221,11 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
        if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) {
                const char *slash;
 
-               if (!cf || !cf->path)
+               if (!kvi || !kvi->path)
                        return error(_("relative config include "
                                       "conditionals must come from files"));
 
-               strbuf_realpath(&path, cf->path, 1);
+               strbuf_realpath(&path, kvi->path, 1);
                slash = find_last_dir_sep(path.buf);
                if (!slash)
                        BUG("how is this possible?");
@@ -245,7 +240,8 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
        return prefix;
 }
 
-static int include_by_gitdir(const struct config_options *opts,
+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)
 {
        struct strbuf text = STRBUF_INIT;
@@ -261,7 +257,7 @@ static int include_by_gitdir(const struct config_options *opts,
 
        strbuf_realpath(&text, git_dir, 1);
        strbuf_add(&pattern, cond, cond_len);
-       prefix = prepare_include_condition_pattern(&pattern);
+       prefix = prepare_include_condition_pattern(kvi, &pattern);
 
 again:
        if (prefix < 0)
@@ -323,7 +319,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;
@@ -342,27 +339,17 @@ static void populate_remote_urls(struct config_include_data *inc)
 {
        struct config_options opts;
 
-       struct config_source *store_cf = cf;
-       struct key_value_info *store_kvi = current_config_kvi;
-       enum config_scope store_scope = current_parsing_scope;
-
        opts = *inc->opts;
        opts.unconditional_remote_url = 1;
 
-       cf = NULL;
-       current_config_kvi = NULL;
-       current_parsing_scope = 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);
-
-       cf = store_cf;
-       current_config_kvi = store_kvi;
-       current_parsing_scope = 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;
@@ -406,15 +393,16 @@ static int include_by_remote_url(struct config_include_data *inc,
                                             inc->remote_urls);
 }
 
-static int include_condition_is_true(struct config_include_data *inc,
+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(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(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,
@@ -425,7 +413,9 @@ static int include_condition_is_true(struct config_include_data *inc,
        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;
        const char *cond, *key;
@@ -436,21 +426,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(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(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(value, inc);
+               ret = handle_path_include(ctx->kvi, value, inc);
                inc->fn = old_fn;
        }
 
@@ -608,27 +598,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])
@@ -647,12 +655,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) {
@@ -686,7 +695,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 {
@@ -710,13 +719,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;
-
-       memset(&source, 0, sizeof(source));
-       source.prev = cf;
-       source.origin_type = CONFIG_ORIGIN_CMDLINE;
-       cf = &source;
+       struct key_value_info kvi = KVI_INIT;
 
+       kvi_from_param(&kvi);
        env = getenv(CONFIG_COUNT_ENVIRONMENT);
        if (env) {
                unsigned long count;
@@ -752,7 +757,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;
                        }
@@ -763,7 +768,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;
                }
@@ -773,25 +778,24 @@ out:
        strbuf_release(&envvar);
        strvec_clear(&to_free);
        free(envw);
-       cf = source.prev;
        return ret;
 }
 
-static int get_next_char(void)
+static int get_next_char(struct config_source *cs)
 {
-       int c = cf->do_fgetc(cf);
+       int c = cs->do_fgetc(cs);
 
        if (c == '\r') {
                /* DOS like systems */
-               c = cf->do_fgetc(cf);
+               c = cs->do_fgetc(cs);
                if (c != '\n') {
                        if (c != EOF)
-                               cf->do_ungetc(c, cf);
+                               cs->do_ungetc(c, cs);
                        c = '\r';
                }
        }
 
-       if (c != EOF && ++cf->total_len > INT_MAX) {
+       if (c != EOF && ++cs->total_len > INT_MAX) {
                /*
                 * This is an absurdly long config file; refuse to parse
                 * further in order to protect downstream code from integer
@@ -799,38 +803,38 @@ static int get_next_char(void)
                 * but we can mark EOF and put trash in the return value,
                 * which will trigger a parse error.
                 */
-               cf->eof = 1;
+               cs->eof = 1;
                return 0;
        }
 
        if (c == '\n')
-               cf->linenr++;
+               cs->linenr++;
        if (c == EOF) {
-               cf->eof = 1;
-               cf->linenr++;
+               cs->eof = 1;
+               cs->linenr++;
                c = '\n';
        }
        return c;
 }
 
-static char *parse_value(void)
+static char *parse_value(struct config_source *cs)
 {
        int quote = 0, comment = 0, space = 0;
 
-       strbuf_reset(&cf->value);
+       strbuf_reset(&cs->value);
        for (;;) {
-               int c = get_next_char();
+               int c = get_next_char(cs);
                if (c == '\n') {
                        if (quote) {
-                               cf->linenr--;
+                               cs->linenr--;
                                return NULL;
                        }
-                       return cf->value.buf;
+                       return cs->value.buf;
                }
                if (comment)
                        continue;
                if (isspace(c) && !quote) {
-                       if (cf->value.len)
+                       if (cs->value.len)
                                space++;
                        continue;
                }
@@ -841,9 +845,9 @@ static char *parse_value(void)
                        }
                }
                for (; space; space--)
-                       strbuf_addch(&cf->value, ' ');
+                       strbuf_addch(&cs->value, ' ');
                if (c == '\\') {
-                       c = get_next_char();
+                       c = get_next_char(cs);
                        switch (c) {
                        case '\n':
                                continue;
@@ -863,27 +867,31 @@ static char *parse_value(void)
                        default:
                                return NULL;
                        }
-                       strbuf_addch(&cf->value, c);
+                       strbuf_addch(&cs->value, c);
                        continue;
                }
                if (c == '"') {
                        quote = 1-quote;
                        continue;
                }
-               strbuf_addch(&cf->value, c);
+               strbuf_addch(&cs->value, c);
        }
 }
 
-static int get_value(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 (;;) {
-               c = get_next_char();
-               if (cf->eof)
+               c = get_next_char(cs);
+               if (cs->eof)
                        break;
                if (!iskeychar(c))
                        break;
@@ -891,13 +899,13 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
        }
 
        while (c == ' ' || c == '\t')
-               c = get_next_char();
+               c = get_next_char(cs);
 
        value = NULL;
        if (c != '\n') {
                if (c != '=')
                        return -1;
-               value = parse_value();
+               value = parse_value(cs);
                if (!value)
                        return -1;
        }
@@ -906,20 +914,22 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
         * the line we just parsed during the call to fn to get
         * accurate line number in error messages.
         */
-       cf->linenr--;
-       ret = fn(name->buf, value, data);
+       cs->linenr--;
+       kvi->linenr = cs->linenr;
+       ret = fn(name->buf, value, &ctx, data);
        if (ret >= 0)
-               cf->linenr++;
+               cs->linenr++;
        return ret;
 }
 
-static int get_extended_base_var(struct strbuf *name, int c)
+static int get_extended_base_var(struct config_source *cs, struct strbuf *name,
+                                int c)
 {
-       cf->subsection_case_sensitive = 0;
+       cs->subsection_case_sensitive = 0;
        do {
                if (c == '\n')
                        goto error_incomplete_line;
-               c = get_next_char();
+               c = get_next_char(cs);
        } while (isspace(c));
 
        /* We require the format to be '[base "extension"]' */
@@ -928,13 +938,13 @@ static int get_extended_base_var(struct strbuf *name, int c)
        strbuf_addch(name, '.');
 
        for (;;) {
-               int c = get_next_char();
+               int c = get_next_char(cs);
                if (c == '\n')
                        goto error_incomplete_line;
                if (c == '"')
                        break;
                if (c == '\\') {
-                       c = get_next_char();
+                       c = get_next_char(cs);
                        if (c == '\n')
                                goto error_incomplete_line;
                }
@@ -942,25 +952,25 @@ static int get_extended_base_var(struct strbuf *name, int c)
        }
 
        /* Final ']' */
-       if (get_next_char() != ']')
+       if (get_next_char(cs) != ']')
                return -1;
        return 0;
 error_incomplete_line:
-       cf->linenr--;
+       cs->linenr--;
        return -1;
 }
 
-static int get_base_var(struct strbuf *name)
+static int get_base_var(struct config_source *cs, struct strbuf *name)
 {
-       cf->subsection_case_sensitive = 1;
+       cs->subsection_case_sensitive = 1;
        for (;;) {
-               int c = get_next_char();
-               if (cf->eof)
+               int c = get_next_char(cs);
+               if (cs->eof)
                        return -1;
                if (c == ']')
                        return 0;
                if (isspace(c))
-                       return get_extended_base_var(name, c);
+                       return get_extended_base_var(cs, name, c);
                if (!iskeychar(c) && c != '.')
                        return -1;
                strbuf_addch(name, tolower(c));
@@ -973,7 +983,8 @@ struct parse_event_data {
        const struct config_options *opts;
 };
 
-static int do_event(enum config_event_t type, struct parse_event_data *data)
+static int do_event(struct config_source *cs, enum config_event_t type,
+                   struct parse_event_data *data)
 {
        size_t offset;
 
@@ -984,7 +995,7 @@ static int do_event(enum config_event_t type, struct parse_event_data *data)
            data->previous_type == type)
                return 0;
 
-       offset = cf->do_ftell(cf);
+       offset = cs->do_ftell(cs);
        /*
         * At EOF, the parser always "inserts" an extra '\n', therefore
         * the end offset of the event is the current file position, otherwise
@@ -995,7 +1006,7 @@ static int do_event(enum config_event_t type, struct parse_event_data *data)
 
        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;
@@ -1004,12 +1015,24 @@ static int do_event(enum config_event_t type, struct parse_event_data *data)
        return 0;
 }
 
-static int git_parse_source(config_fn_t fn, void *data,
+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,
+                           struct key_value_info *kvi, void *data,
                            const struct config_options *opts)
 {
        int comment = 0;
        size_t baselen = 0;
-       struct strbuf *var = &cf->var;
+       struct strbuf *var = &cs->var;
        int error_return = 0;
        char *error_msg = NULL;
 
@@ -1024,7 +1047,7 @@ static int git_parse_source(config_fn_t fn, void *data,
        for (;;) {
                int c;
 
-               c = get_next_char();
+               c = get_next_char(cs);
                if (bomptr && *bomptr) {
                        /* We are at the file beginning; skip UTF8-encoded BOM
                         * if present. Sane editors won't put this in on their
@@ -1041,12 +1064,12 @@ static int git_parse_source(config_fn_t fn, void *data,
                        }
                }
                if (c == '\n') {
-                       if (cf->eof) {
-                               if (do_event(CONFIG_EVENT_EOF, &event_data) < 0)
+                       if (cs->eof) {
+                               if (do_event(cs, CONFIG_EVENT_EOF, &event_data) < 0)
                                        return -1;
                                return 0;
                        }
-                       if (do_event(CONFIG_EVENT_WHITESPACE, &event_data) < 0)
+                       if (do_event(cs, CONFIG_EVENT_WHITESPACE, &event_data) < 0)
                                return -1;
                        comment = 0;
                        continue;
@@ -1054,23 +1077,23 @@ static int git_parse_source(config_fn_t fn, void *data,
                if (comment)
                        continue;
                if (isspace(c)) {
-                       if (do_event(CONFIG_EVENT_WHITESPACE, &event_data) < 0)
+                       if (do_event(cs, CONFIG_EVENT_WHITESPACE, &event_data) < 0)
                                        return -1;
                        continue;
                }
                if (c == '#' || c == ';') {
-                       if (do_event(CONFIG_EVENT_COMMENT, &event_data) < 0)
+                       if (do_event(cs, CONFIG_EVENT_COMMENT, &event_data) < 0)
                                        return -1;
                        comment = 1;
                        continue;
                }
                if (c == '[') {
-                       if (do_event(CONFIG_EVENT_SECTION, &event_data) < 0)
+                       if (do_event(cs, CONFIG_EVENT_SECTION, &event_data) < 0)
                                        return -1;
 
                        /* Reset prior to determining a new stem */
                        strbuf_reset(var);
-                       if (get_base_var(var) < 0 || var->len < 1)
+                       if (get_base_var(cs, var) < 0 || var->len < 1)
                                break;
                        strbuf_addch(var, '.');
                        baselen = var->len;
@@ -1079,7 +1102,7 @@ static int git_parse_source(config_fn_t fn, void *data,
                if (!isalpha(c))
                        break;
 
-               if (do_event(CONFIG_EVENT_ENTRY, &event_data) < 0)
+               if (do_event(cs, CONFIG_EVENT_ENTRY, &event_data) < 0)
                        return -1;
 
                /*
@@ -1089,42 +1112,42 @@ static int git_parse_source(config_fn_t fn, void *data,
                 */
                strbuf_setlen(var, baselen);
                strbuf_addch(var, tolower(c));
-               if (get_value(fn, data, var) < 0)
+               if (get_value(cs, kvi, fn, data, var) < 0)
                        break;
        }
 
-       if (do_event(CONFIG_EVENT_ERROR, &event_data) < 0)
+       if (do_event(cs, CONFIG_EVENT_ERROR, &event_data) < 0)
                return -1;
 
-       switch (cf->origin_type) {
+       switch (cs->origin_type) {
        case CONFIG_ORIGIN_BLOB:
                error_msg = xstrfmt(_("bad config line %d in blob %s"),
-                                     cf->linenr, cf->name);
+                                     cs->linenr, cs->name);
                break;
        case CONFIG_ORIGIN_FILE:
                error_msg = xstrfmt(_("bad config line %d in file %s"),
-                                     cf->linenr, cf->name);
+                                     cs->linenr, cs->name);
                break;
        case CONFIG_ORIGIN_STDIN:
                error_msg = xstrfmt(_("bad config line %d in standard input"),
-                                     cf->linenr);
+                                     cs->linenr);
                break;
        case CONFIG_ORIGIN_SUBMODULE_BLOB:
                error_msg = xstrfmt(_("bad config line %d in submodule-blob %s"),
-                                      cf->linenr, cf->name);
+                                      cs->linenr, cs->name);
                break;
        case CONFIG_ORIGIN_CMDLINE:
                error_msg = xstrfmt(_("bad config line %d in command line %s"),
-                                      cf->linenr, cf->name);
+                                      cs->linenr, cs->name);
                break;
        default:
                error_msg = xstrfmt(_("bad config line %d in %s"),
-                                     cf->linenr, cf->name);
+                                     cs->linenr, cs->name);
        }
 
        switch (opts && opts->error_action ?
                opts->error_action :
-               cf->default_error_action) {
+               cs->default_error_action) {
        case CONFIG_ERROR_DIE:
                die("%s", error_msg);
                break;
@@ -1266,69 +1289,77 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)
 }
 
 NORETURN
-static void die_bad_number(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");
 
+       if (!kvi)
+               BUG("kvi should not be NULL");
+
        if (!value)
                value = "";
 
-       if (!(cf && cf->name))
+       if (!kvi->filename)
                die(_(bad_numeric), value, name, _(error_type));
 
-       switch (cf->origin_type) {
+       switch (kvi->origin_type) {
        case CONFIG_ORIGIN_BLOB:
                die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
-                   value, name, cf->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, cf->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, cf->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, cf->name, _(error_type));
+                   value, name, kvi->filename, _(error_type));
        default:
                die(_("bad numeric config value '%s' for '%s' in %s: %s"),
-                   value, name, cf->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(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(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(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(name, value);
+               die_bad_number(name, value, kvi);
        return ret;
 }
 
@@ -1433,7 +1464,8 @@ int git_parse_maybe_bool(const char *value)
        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) {
@@ -1441,7 +1473,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)
@@ -1489,7 +1521,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")) {
@@ -1566,7 +1599,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;
@@ -1578,7 +1611,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)
@@ -1589,7 +1622,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)
@@ -1603,7 +1636,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;
@@ -1614,17 +1647,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;
        }
 
@@ -1683,7 +1716,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
                        comment_line_char = value[0];
                        auto_comment_line_char = 0;
                } else
-                       return error(_("core.commentChar should only be one character"));
+                       return error(_("core.commentChar should only be one ASCII character"));
                return 0;
        }
 
@@ -1768,13 +1801,8 @@ 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);
-               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)
@@ -1876,15 +1904,16 @@ 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)
+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);
@@ -1907,12 +1936,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)
@@ -1934,36 +1963,36 @@ 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_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 */
-       top->prev = cf;
        top->linenr = 1;
        top->eof = 0;
        top->total_len = 0;
        strbuf_init(&top->value, 1024);
        strbuf_init(&top->var, 1024);
-       cf = top;
+       kvi_from_source(top, scope, &kvi);
 
-       ret = git_parse_source(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);
-       cf = top->prev;
 
        return ret;
 }
 
 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)
+                              const enum config_origin_type origin_type,
+                              const char *name, const char *path, FILE *f,
+                              void *data, enum config_scope scope,
+                              const struct config_options *opts)
 {
-       struct config_source top;
+       struct config_source top = CONFIG_SOURCE_INIT;
        int ret;
 
        top.u.file = f;
@@ -1976,19 +2005,20 @@ static int do_config_from_file(config_fn_t fn,
        top.do_ftell = config_file_ftell;
 
        flockfile(f);
-       ret = do_config_from(&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(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin,
-                                  data, NULL);
+                                  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;
@@ -1999,7 +2029,7 @@ int git_config_from_file_with_options(config_fn_t fn, const char *filename,
        f = fopen_or_warn(filename, "r");
        if (f) {
                ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename,
-                                         filename, f, data, opts);
+                                         filename, f, data, scope, opts);
                fclose(f);
        }
        return ret;
@@ -2007,15 +2037,17 @@ 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;
+       struct config_source top = CONFIG_SOURCE_INIT;
 
        top.u.buf.buf = buf;
        top.u.buf.len = len;
@@ -2028,14 +2060,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(&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;
@@ -2051,7 +2084,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;
@@ -2060,13 +2093,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)
@@ -2120,6 +2154,7 @@ int git_config_system(void)
 }
 
 static int do_git_config_sequence(const struct config_options *opts,
+                                 const struct repository *repo,
                                  config_fn_t fn, void *data)
 {
        int ret = 0;
@@ -2127,57 +2162,68 @@ static int do_git_config_sequence(const struct config_options *opts,
        char *xdg_config = NULL;
        char *user_config = NULL;
        char *repo_config;
-       enum config_scope prev_parsing_scope = current_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;
+       }
 
-       current_parsing_scope = 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);
 
-       current_parsing_scope = 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);
 
-       current_parsing_scope = 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);
 
-       current_parsing_scope = 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);
        }
 
-       current_parsing_scope = CONFIG_SCOPE_COMMAND;
        if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
                die(_("unable to parse command-line config"));
 
-       current_parsing_scope = 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;
@@ -2187,29 +2233,27 @@ int config_with_options(config_fn_t fn, void *data,
                inc.fn = fn;
                inc.data = data;
                inc.opts = opts;
+               inc.repo = repo;
                inc.config_source = config_source;
                fn = git_config_include;
                data = &inc;
        }
 
-       if (config_source)
-               current_parsing_scope = 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(opts, fn, data);
+               ret = do_git_config_sequence(opts, repo, fn, data);
        }
 
        if (inc.remote_urls) {
@@ -2219,26 +2263,24 @@ int config_with_options(config_fn_t fn, void *data,
        return ret;
 }
 
-static void configset_iter(struct config_set *cs, 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 = &cs->list;
+       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;
 
-               current_config_kvi = 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,
-                                             current_config_kvi->filename,
-                                             current_config_kvi->linenr);
-
-               current_config_kvi = NULL;
+                                             ctx.kvi->filename,
+                                             ctx.kvi->linenr);
        }
 }
 
@@ -2266,7 +2308,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);
@@ -2286,36 +2328,47 @@ 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);
 }
 
-static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
+RESULT_MUST_BE_USED
+static int configset_find_element(struct config_set *set, const char *key,
+                                 struct config_set_element **dest)
 {
        struct config_set_element k;
        struct config_set_element *found_entry;
        char *normalized_key;
+       int ret;
+
        /*
         * `key` may come from the user, so normalize it before using it
         * for querying entries from the hashmap.
         */
-       if (git_config_parse_key(key, &normalized_key, NULL))
-               return NULL;
+       ret = git_config_parse_key(key, &normalized_key, NULL);
+       if (ret)
+               return ret;
 
        hashmap_entry_init(&k.ent, strhash(normalized_key));
        k.key = normalized_key;
-       found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);
+       found_entry = hashmap_get_entry(&set->config_hash, &k, ent, NULL);
        free(normalized_key);
-       return found_entry;
+       *dest = found_entry;
+       return 0;
 }
 
-static int configset_add_value(struct config_set *cs, const char *key, const char *value)
+static int configset_add_value(const struct key_value_info *kvi_p,
+                              struct config_set *set, const char *key,
+                              const char *value)
 {
        struct config_set_element *e;
        struct string_list_item *si;
        struct configset_list_item *l_item;
        struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
+       int ret;
 
-       e = configset_find_element(cs, key);
+       ret = configset_find_element(set, key, &e);
+       if (ret)
+               return ret;
        /*
         * Since the keys are being fed by git_config*() callback mechanism, they
         * are already normalized. So simply add them without any further munging.
@@ -2325,28 +2378,16 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
                hashmap_entry_init(&e->ent, strhash(key));
                e->key = xstrdup(key);
                string_list_init_dup(&e->value_list);
-               hashmap_add(&cs->config_hash, &e->ent);
+               hashmap_add(&set->config_hash, &e->ent);
        }
        si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
 
-       ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
-       l_item = &cs->list.items[cs->list.nr++];
+       ALLOC_GROW(set->list.items, set->list.nr + 1, set->list.alloc);
+       l_item = &set->list.items[set->list.nr++];
        l_item->e = e;
        l_item->value_index = e->value_list.nr - 1;
 
-       if (!cf)
-               BUG("configset_add_value has no source");
-       if (cf->name) {
-               kv_info->filename = strintern(cf->name);
-               kv_info->linenr = cf->linenr;
-               kv_info->origin_type = cf->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 = current_parsing_scope;
+       *kv_info = *kvi_p;
        si->util = kv_info;
 
        return 0;
@@ -2365,84 +2406,131 @@ static int config_set_element_cmp(const void *cmp_data UNUSED,
        return strcmp(e1->key, e2->key);
 }
 
-void git_configset_init(struct config_set *cs)
+void git_configset_init(struct config_set *set)
 {
-       hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0);
-       cs->hash_initialized = 1;
-       cs->list.nr = 0;
-       cs->list.alloc = 0;
-       cs->list.items = NULL;
+       hashmap_init(&set->config_hash, config_set_element_cmp, NULL, 0);
+       set->hash_initialized = 1;
+       set->list.nr = 0;
+       set->list.alloc = 0;
+       set->list.items = NULL;
 }
 
-void git_configset_clear(struct config_set *cs)
+void git_configset_clear(struct config_set *set)
 {
        struct config_set_element *entry;
        struct hashmap_iter iter;
-       if (!cs->hash_initialized)
+       if (!set->hash_initialized)
                return;
 
-       hashmap_for_each_entry(&cs->config_hash, &iter, entry,
+       hashmap_for_each_entry(&set->config_hash, &iter, entry,
                                ent /* member name */) {
                free(entry->key);
                string_list_clear(&entry->value_list, 1);
        }
-       hashmap_clear_and_free(&cs->config_hash, struct config_set_element, ent);
-       cs->hash_initialized = 0;
-       free(cs->list.items);
-       cs->list.nr = 0;
-       cs->list.alloc = 0;
-       cs->list.items = NULL;
+       hashmap_clear_and_free(&set->config_hash, struct config_set_element, ent);
+       set->hash_initialized = 0;
+       free(set->list.items);
+       set->list.nr = 0;
+       set->list.alloc = 0;
+       set->list.items = NULL;
 }
 
-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 config_set *cs = cb;
-       configset_add_value(cs, 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 *cs, const char *filename)
+int git_configset_add_file(struct config_set *set, const char *filename)
 {
-       return git_config_from_file(config_set_callback, filename, cs);
+       return git_config_from_file(config_set_callback, filename, set);
 }
 
-int git_configset_get_value(struct config_set *cs, 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
         * value in the value list for that key.
         */
-       values = git_configset_get_value_multi(cs, key);
+       if ((ret = git_configset_get_value_multi(set, key, &values)))
+               return ret;
 
-       if (!values)
-               return 1;
        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;
 }
 
-const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
+int git_configset_get_value_multi(struct config_set *set, const char *key,
+                                 const struct string_list **dest)
 {
-       struct config_set_element *e = configset_find_element(cs, key);
-       return e ? &e->value_list : NULL;
+       struct config_set_element *e;
+       int ret;
+
+       if ((ret = configset_find_element(set, key, &e)))
+               return ret;
+       else if (!e)
+               return 1;
+       *dest = &e->value_list;
+
+       return 0;
 }
 
-int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
+static int check_multi_string(struct string_list_item *item, void *util)
+{
+       return item->string ? 0 : config_error_nonbool(util);
+}
+
+int git_configset_get_string_multi(struct config_set *cs, const char *key,
+                                  const struct string_list **dest)
+{
+       int ret;
+
+       if ((ret = git_configset_get_value_multi(cs, key, dest)))
+               return ret;
+       if ((ret = for_each_string_list((struct string_list *)*dest,
+                                       check_multi_string, (void *)key)))
+               return ret;
+
+       return 0;
+}
+
+int git_configset_get(struct config_set *set, const char *key)
+{
+       struct config_set_element *e;
+       int ret;
+
+       if ((ret = configset_find_element(set, key, &e)))
+               return ret;
+       else if (!e)
+               return 1;
+       return 0;
+}
+
+int git_configset_get_string(struct config_set *set, const char *key, char **dest)
 {
        const char *value;
-       if (!git_configset_get_value(cs, key, &value))
+       if (!git_configset_get_value(set, key, &value, NULL))
                return git_config_string((const char **)dest, key, value);
        else
                return 1;
 }
 
-static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
+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(cs, key, &value)) {
+       if (!git_configset_get_value(set, key, &value, NULL)) {
                if (!value)
                        return config_error_nonbool(key);
                *dest = value;
@@ -2452,51 +2540,57 @@ static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
        }
 }
 
-int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
+int git_configset_get_int(struct config_set *set, const char *key, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(cs, 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;
 }
 
-int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest)
+int git_configset_get_ulong(struct config_set *set, const char *key, unsigned long *dest)
 {
        const char *value;
-       if (!git_configset_get_value(cs, 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;
 }
 
-int git_configset_get_bool(struct config_set *cs, const char *key, int *dest)
+int git_configset_get_bool(struct config_set *set, const char *key, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(cs, key, &value)) {
+       if (!git_configset_get_value(set, key, &value, NULL)) {
                *dest = git_config_bool(key, value);
                return 0;
        } else
                return 1;
 }
 
-int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
+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(cs, 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;
 }
 
-int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest)
+int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(cs, key, &value)) {
+       if (!git_configset_get_value(set, key, &value, NULL)) {
                *dest = git_parse_maybe_bool(value);
                if (*dest == -1)
                        return -1;
@@ -2505,10 +2599,10 @@ int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *de
                return 1;
 }
 
-int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest)
+int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
 {
        const char *value;
-       if (!git_configset_get_value(cs, key, &value))
+       if (!git_configset_get_value(set, key, &value, NULL))
                return git_config_pathname(dest, key, value);
        else
                return 1;
@@ -2529,8 +2623,8 @@ static void repo_read_config(struct repository *repo)
                git_configset_clear(repo->config);
 
        git_configset_init(repo->config);
-
-       if (config_with_options(config_set_callback, repo->config, 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
@@ -2565,18 +2659,31 @@ void repo_config(struct repository *repo, config_fn_t fn, void *data)
        configset_iter(repo->config, fn, data);
 }
 
+int repo_config_get(struct repository *repo, const char *key)
+{
+       git_config_check_init(repo);
+       return git_configset_get(repo->config, key);
+}
+
 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);
 }
 
-const struct string_list *repo_config_get_value_multi(struct repository *repo,
-                                                     const char *key)
+int repo_config_get_value_multi(struct repository *repo, const char *key,
+                               const struct string_list **dest)
 {
        git_config_check_init(repo);
-       return git_configset_get_value_multi(repo->config, key);
+       return git_configset_get_value_multi(repo->config, key, dest);
+}
+
+int repo_config_get_string_multi(struct repository *repo, const char *key,
+                                const struct string_list **dest)
+{
+       git_config_check_init(repo);
+       return git_configset_get_string_multi(repo->config, key, dest);
 }
 
 int repo_config_get_string(struct repository *repo,
@@ -2656,8 +2763,9 @@ static void read_protected_config(void)
                .ignore_worktree = 1,
                .system_gently = 1,
        };
+
        git_configset_init(&protected_config);
-       config_with_options(config_set_callback, &protected_config,
+       config_with_options(config_set_callback, &protected_config, NULL,
                            NULL, &opts);
 }
 
@@ -2679,14 +2787,25 @@ void git_config_clear(void)
        repo_config_clear(the_repository);
 }
 
+int git_config_get(const char *key)
+{
+       return repo_config_get(the_repository, key);
+}
+
 int git_config_get_value(const char *key, const char **value)
 {
        return repo_config_get_value(the_repository, key, value);
 }
 
-const struct string_list *git_config_get_value_multi(const char *key)
+int git_config_get_value_multi(const char *key, const struct string_list **dest)
 {
-       return repo_config_get_value_multi(the_repository, key);
+       return repo_config_get_value_multi(the_repository, key, dest);
+}
+
+int git_config_get_string_multi(const char *key,
+                               const struct string_list **dest)
+{
+       return repo_config_get_string_multi(the_repository, key, dest);
 }
 
 int git_config_get_string(const char *key, char **dest)
@@ -2833,7 +2952,8 @@ void git_die_config(const char *key, const char *err, ...)
                error_fn(err, params);
                va_end(params);
        }
-       values = git_config_get_value_multi(key);
+       if (git_config_get_value_multi(key, &values))
+               BUG("for key '%s' we must have a value to report on", key);
        kv_info = values->items[values->nr - 1].util;
        git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
 }
@@ -2857,6 +2977,7 @@ struct config_store_data {
        unsigned int parsed_nr, parsed_alloc, *seen, seen_nr, seen_alloc;
        unsigned int key_seen:1, section_seen:1, is_keys_section:1;
 };
+#define CONFIG_STORE_INIT { 0 }
 
 static void config_store_data_clear(struct config_store_data *store)
 {
@@ -2887,8 +3008,8 @@ 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;
 
@@ -2900,10 +3021,10 @@ static int store_aux_event(enum config_event_t type,
        if (type == CONFIG_EVENT_SECTION) {
                int (*cmpfn)(const char *, const char *, size_t);
 
-               if (cf->var.len < 2 || cf->var.buf[cf->var.len - 1] != '.')
-                       return error(_("invalid section name '%s'"), cf->var.buf);
+               if (cs->var.len < 2 || cs->var.buf[cs->var.len - 1] != '.')
+                       return error(_("invalid section name '%s'"), cs->var.buf);
 
-               if (cf->subsection_case_sensitive)
+               if (cs->subsection_case_sensitive)
                        cmpfn = strncasecmp;
                else
                        cmpfn = strncmp;
@@ -2911,8 +3032,8 @@ static int store_aux_event(enum config_event_t type,
                /* Is this the section we were looking for? */
                store->is_keys_section =
                        store->parsed[store->parsed_nr].is_keys_section =
-                       cf->var.len - 1 == store->baselen &&
-                       !cmpfn(cf->var.buf, store->key, store->baselen);
+                       cs->var.len - 1 == store->baselen &&
+                       !cmpfn(cs->var.buf, store->key, store->baselen);
                if (store->is_keys_section) {
                        store->section_seen = 1;
                        ALLOC_GROW(store->seen, store->seen_nr + 1,
@@ -2926,7 +3047,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;
 
@@ -3155,7 +3277,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);
@@ -3208,9 +3330,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
        char *filename_buf = NULL;
        char *contents = NULL;
        size_t contents_sz;
-       struct config_store_data store;
-
-       memset(&store, 0, sizeof(store));
+       struct config_store_data store = CONFIG_STORE_INIT;
 
        /* parse-key returns negative; flip the sign to feed exit(3) */
        ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
@@ -3300,7 +3420,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;
@@ -3661,6 +3782,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);
                                }
                        }
@@ -3707,6 +3829,7 @@ out_no_rollback:
        free(filename_buf);
        config_store_data_clear(&store);
        strbuf_release(&buf);
+       strbuf_release(&copystr);
        return ret;
 }
 
@@ -3780,16 +3903,8 @@ int parse_config_key(const char *var,
        return 0;
 }
 
-const char *current_config_origin_type(void)
+const char *config_origin_type_name(enum config_origin_type type)
 {
-       int type;
-       if (current_config_kvi)
-               type = current_config_kvi->origin_type;
-       else if(cf)
-               type = cf->origin_type;
-       else
-               BUG("current_config_origin_type called outside config callback");
-
        switch (type) {
        case CONFIG_ORIGIN_BLOB:
                return "blob";
@@ -3826,34 +3941,6 @@ const char *config_scope_name(enum config_scope scope)
        }
 }
 
-const char *current_config_name(void)
-{
-       const char *name;
-       if (current_config_kvi)
-               name = current_config_kvi->filename;
-       else if (cf)
-               name = cf->name;
-       else
-               BUG("current_config_name called outside config callback");
-       return name ? name : "";
-}
-
-enum config_scope current_config_scope(void)
-{
-       if (current_config_kvi)
-               return current_config_kvi->scope;
-       else
-               return current_parsing_scope;
-}
-
-int current_config_line(void)
-{
-       if (current_config_kvi)
-               return current_config_kvi->linenr;
-       else
-               return cf->linenr;
-}
-
 int lookup_config(const char **mapping, int nr_mapping, const char *var)
 {
        int i;
index 7606246531a798a0f400a38742323626ae0d9524..6332d749047764aff33000d01fc78f75ddfe03b1 100644 (file)
--- a/config.h
+++ b/config.h
@@ -3,6 +3,7 @@
 
 #include "hashmap.h"
 #include "string-list.h"
+#include "repository.h"
 
 
 /**
@@ -49,13 +50,12 @@ 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;
 };
 
 enum config_origin_type {
+       CONFIG_ORIGIN_UNKNOWN = 0,
        CONFIG_ORIGIN_BLOB,
        CONFIG_ORIGIN_FILE,
        CONFIG_ORIGIN_STDIN,
@@ -72,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.
@@ -81,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 {
@@ -100,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 {
@@ -110,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,
@@ -122,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.
@@ -141,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);
@@ -195,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);
 
 /**
@@ -218,22 +257,26 @@ 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
@@ -355,10 +398,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:
@@ -450,10 +491,31 @@ int git_configset_add_file(struct config_set *cs, const char *filename);
 /**
  * Finds and returns the value list, sorted in order of increasing priority
  * for the configuration variable `key` and config set `cs`. When the
- * configuration variable `key` is not found, returns NULL. The caller
- * should not free or modify the returned pointer, as it is owned by the cache.
+ * configuration variable `key` is not found, returns 1 without touching
+ * `value`.
+ *
+ * The key will be parsed for validity with git_config_parse_key(), on
+ * error a negative value will be returned.
+ *
+ * The caller should not free or modify the returned pointer, as it is
+ * owned by the cache.
  */
-const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
+RESULT_MUST_BE_USED
+int git_configset_get_value_multi(struct config_set *cs, const char *key,
+                                 const struct string_list **dest);
+
+/**
+ * A validation wrapper for git_configset_get_value_multi() which does
+ * for it what git_configset_get_string() does for
+ * git_configset_get_value().
+ *
+ * The configuration syntax allows for "[section] key", which will
+ * give us a NULL entry in the "struct string_list", as opposed to
+ * "[section] key =" which is the empty string. Most users of the API
+ * are not prepared to handle NULL in a "struct string_list".
+ */
+int git_configset_get_string_multi(struct config_set *cs, const char *key,
+                                  const struct string_list **dest);
 
 /**
  * Clears `config_set` structure, removes all saved variable-value pairs.
@@ -465,6 +527,13 @@ void git_configset_clear(struct config_set *cs);
  * value in the 'dest' pointer.
  */
 
+/**
+ * git_configset_get() returns negative values on error, see
+ * repo_config_get() below.
+ */
+RESULT_MUST_BE_USED
+int git_configset_get(struct config_set *cs, const char *key);
+
 /*
  * Finds the highest-priority value for the configuration variable `key`
  * and config set `cs`, stores the pointer to it in `value` and returns 0.
@@ -472,7 +541,8 @@ void git_configset_clear(struct config_set *cs);
  * 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);
@@ -485,10 +555,22 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha
 /* Functions for reading a repository's config */
 struct repository;
 void repo_config(struct repository *repo, config_fn_t fn, void *data);
+
+/**
+ * Run only the discover part of the repo_config_get_*() functions
+ * below, in addition to 1 if not found, returns negative values on
+ * error (e.g. if the key itself is invalid).
+ */
+RESULT_MUST_BE_USED
+int repo_config_get(struct repository *repo, const char *key);
 int repo_config_get_value(struct repository *repo,
                          const char *key, const char **value);
-const struct string_list *repo_config_get_value_multi(struct repository *repo,
-                                                     const char *key);
+RESULT_MUST_BE_USED
+int repo_config_get_value_multi(struct repository *repo, const char *key,
+                               const struct string_list **dest);
+RESULT_MUST_BE_USED
+int repo_config_get_string_multi(struct repository *repo, const char *key,
+                                const struct string_list **dest);
 int repo_config_get_string(struct repository *repo,
                           const char *key, char **dest);
 int repo_config_get_string_tmp(struct repository *repo,
@@ -521,8 +603,15 @@ void git_protected_config(config_fn_t fn, void *data);
  * manner, the config API provides two functions `git_config_get_value`
  * and `git_config_get_value_multi`. They both read values from an internal
  * cache generated previously from reading the config files.
+ *
+ * For those git_config_get*() functions that aren't documented,
+ * consult the corresponding repo_config_get*() function's
+ * documentation.
  */
 
+RESULT_MUST_BE_USED
+int git_config_get(const char *key);
+
 /**
  * Finds the highest-priority value for the configuration variable `key`,
  * stores the pointer to it in `value` and returns 0. When the
@@ -535,10 +624,17 @@ int git_config_get_value(const char *key, const char **value);
 /**
  * Finds and returns the value list, sorted in order of increasing priority
  * for the configuration variable `key`. When the configuration variable
- * `key` is not found, returns NULL. The caller should not free or modify
- * the returned pointer, as it is owned by the cache.
+ * `key` is not found, returns 1 without touching `value`.
+ *
+ * The caller should not free or modify the returned pointer, as it is
+ * owned by the cache.
  */
-const struct string_list *git_config_get_value_multi(const char *key);
+RESULT_MUST_BE_USED
+int git_config_get_value_multi(const char *key,
+                              const struct string_list **dest);
+RESULT_MUST_BE_USED
+int git_config_get_string_multi(const char *key,
+                               const struct string_list **dest);
 
 /**
  * Resets and invalidates the config cache.
@@ -612,13 +708,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 63e59641c0d4d5c60fc4bee2761e6acd471535a2..0d77737a5363c39fd71376c0f483bc8808538754 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -1,6 +1,8 @@
 #include "git-compat-util.h"
-#include "cache.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "pkt-line.h"
 #include "quote.h"
 #include "refs.h"
@@ -10,7 +12,9 @@
 #include "url.h"
 #include "string-list.h"
 #include "oid-array.h"
+#include "path.h"
 #include "transport.h"
+#include "trace2.h"
 #include "strbuf.h"
 #include "version.h"
 #include "protocol.h"
@@ -19,7 +23,7 @@
 
 static char *server_capabilities_v1;
 static struct strvec server_capabilities_v2 = STRVEC_INIT;
-static const char *next_server_feature_value(const char *feature, int *len, int *offset);
+static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset);
 
 static int check_ref(const char *name, unsigned int flags)
 {
@@ -30,7 +34,8 @@ static int check_ref(const char *name, unsigned int flags)
                return 0;
 
        /* REF_NORMAL means that we don't want the magic fake tag refs */
-       if ((flags & REF_NORMAL) && check_refname_format(name, 0))
+       if ((flags & REF_NORMAL) && check_refname_format(name,
+                                                        REFNAME_ALLOW_ONELEVEL))
                return 0;
 
        /* REF_HEADS means that we want regular branch heads */
@@ -201,10 +206,10 @@ reject:
 static void annotate_refs_with_symref_info(struct ref *ref)
 {
        struct string_list symref = STRING_LIST_INIT_DUP;
-       int offset = 0;
+       size_t offset = 0;
 
        while (1) {
-               int len;
+               size_t len;
                const char *val;
 
                val = next_server_feature_value("symref", &len, &offset);
@@ -227,7 +232,7 @@ static void annotate_refs_with_symref_info(struct ref *ref)
 static void process_capabilities(struct packet_reader *reader, int *linelen)
 {
        const char *feat_val;
-       int feat_len;
+       size_t feat_len;
        const char *line = reader->line;
        int nul_location = strlen(line);
        if (nul_location == *linelen)
@@ -259,7 +264,8 @@ static int process_dummy_ref(const struct packet_reader *reader)
                return 0;
        name++;
 
-       return oideq(null_oid(), &oid) && !strcmp(name, "capabilities^{}");
+       return oideq(reader->hash_algo->null_oid, &oid) &&
+               !strcmp(name, "capabilities^{}");
 }
 
 static void check_no_capabilities(const char *line, int len)
@@ -591,9 +597,10 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
        return list;
 }
 
-const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
+const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset)
 {
-       int len;
+       const char *orig_start = feature_list;
+       size_t len;
 
        if (!feature_list)
                return NULL;
@@ -612,19 +619,19 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i
                                if (lenp)
                                        *lenp = 0;
                                if (offset)
-                                       *offset = found + len - feature_list;
+                                       *offset = found + len - orig_start;
                                return value;
                        }
                        /* feature with a value (e.g., "agent=git/1.2.3") */
                        else if (*value == '=') {
-                               int end;
+                               size_t end;
 
                                value++;
                                end = strcspn(value, " \t\n");
                                if (lenp)
                                        *lenp = end;
                                if (offset)
-                                       *offset = value + end - feature_list;
+                                       *offset = value + end - orig_start;
                                return value;
                        }
                        /*
@@ -639,8 +646,8 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i
 
 int server_supports_hash(const char *desired, int *feature_supported)
 {
-       int offset = 0;
-       int len;
+       size_t offset = 0;
+       size_t len;
        const char *hash;
 
        hash = next_server_feature_value("object-format", &len, &offset);
@@ -664,12 +671,12 @@ int parse_feature_request(const char *feature_list, const char *feature)
        return !!parse_feature_value(feature_list, feature, NULL, NULL);
 }
 
-static const char *next_server_feature_value(const char *feature, int *len, int *offset)
+static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset)
 {
        return parse_feature_value(server_capabilities_v1, feature, len, offset);
 }
 
-const char *server_feature_value(const char *feature, int *len)
+const char *server_feature_value(const char *feature, size_t *len)
 {
        return parse_feature_value(server_capabilities_v1, feature, len, NULL);
 }
@@ -958,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;
@@ -1004,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)
@@ -1406,6 +1413,7 @@ static void fill_ssh_args(struct child_process *conn, const char *ssh_host,
  * the connection failed).
  */
 struct child_process *git_connect(int fd[2], const char *url,
+                                 const char *name,
                                  const char *prog, int flags)
 {
        char *hostandport, *path;
@@ -1415,10 +1423,11 @@ struct child_process *git_connect(int fd[2], const char *url,
 
        /*
         * NEEDSWORK: If we are trying to use protocol v2 and we are planning
-        * to perform a push, then fallback to v0 since the client doesn't know
-        * how to push yet using v2.
+        * to perform any operation that doesn't involve upload-pack (i.e., a
+        * fetch, ls-remote, etc), then fallback to v0 since we don't know how
+        * to do anything else (like push or remote archive) via v2.
         */
-       if (version == protocol_v2 && !strcmp("git-receive-pack", prog))
+       if (version == protocol_v2 && strcmp("git-upload-pack", name))
                version = protocol_v0;
 
        /* Without this we cannot rely on waitpid() to tell
index b26f7de7841838e0d6e88bb81169191f579fb56d..1645126c17f889659d84174210a43939ef67507f 100644 (file)
--- a/connect.h
+++ b/connect.h
@@ -7,19 +7,19 @@
 #define CONNECT_DIAG_URL      (1u << 1)
 #define CONNECT_IPV4          (1u << 2)
 #define CONNECT_IPV6          (1u << 3)
-struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
+struct child_process *git_connect(int fd[2], const char *url, const char *name, const char *prog, int flags);
 int finish_connect(struct child_process *conn);
 int git_connection_is_socket(struct child_process *conn);
 int server_supports(const char *feature);
 int parse_feature_request(const char *features, const char *feature);
-const char *server_feature_value(const char *feature, int *len_ret);
+const char *server_feature_value(const char *feature, size_t *len_ret);
 int url_is_local_not_ssh(const char *url);
 
 struct packet_reader;
 enum protocol_version discover_version(struct packet_reader *reader);
 
 int server_supports_hash(const char *desired, int *feature_supported);
-const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset);
+const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset);
 int server_supports_v2(const char *c);
 void ensure_server_supports_v2(const char *c);
 int server_feature_v2(const char *c, const char **v);
index b90fd61790cef00d4141bb2eb30f33522e6e8c47..8f89376dbcf30cd2cf69c3d2eaa446e47c9f4ae8 100644 (file)
@@ -1,5 +1,7 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
 #include "run-command.h"
 #include "sigchain.h"
 #include "connected.h"
@@ -54,7 +56,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
                strbuf_release(&idx_file);
        }
 
-       if (has_promisor_remote()) {
+       if (repo_has_promisor_remote(the_repository)) {
                /*
                 * For partial clones, we don't want to have to do a regular
                 * connectivity check because we have to enumerate and exclude
@@ -97,7 +99,7 @@ no_promisor_pack_found:
        strvec_push(&rev_list.args,"rev-list");
        strvec_push(&rev_list.args, "--objects");
        strvec_push(&rev_list.args, "--stdin");
-       if (has_promisor_remote())
+       if (repo_has_promisor_remote(the_repository))
                strvec_push(&rev_list.args, "--exclude-promisor-objects");
        if (!opt->is_deepening_fetch) {
                strvec_push(&rev_list.args, "--not");
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
+  )
+)
diff --git a/contrib/coccinelle/tests/unused.c b/contrib/coccinelle/tests/unused.c
deleted file mode 100644 (file)
index 8294d73..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-void test_strbuf(void)
-{
-       struct strbuf sb1 = STRBUF_INIT;
-       struct strbuf sb2 = STRBUF_INIT;
-       struct strbuf sb3 = STRBUF_INIT;
-       struct strbuf sb4 = STRBUF_INIT;
-       struct strbuf sb5;
-       struct strbuf sb6 = { 0 };
-       struct strbuf sb7 = STRBUF_INIT;
-       struct strbuf sb8 = STRBUF_INIT;
-       struct strbuf *sp1;
-       struct strbuf *sp2;
-       struct strbuf *sp3;
-       struct strbuf *sp4 = xmalloc(sizeof(struct strbuf));
-       struct strbuf *sp5 = xmalloc(sizeof(struct strbuf));
-       struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
-       struct strbuf *sp7;
-
-       strbuf_init(&sb5, 0);
-       strbuf_init(sp1, 0);
-       strbuf_init(sp2, 0);
-       strbuf_init(sp3, 0);
-       strbuf_init(sp4, 0);
-       strbuf_init(sp5, 0);
-       strbuf_init(sp6, 0);
-       strbuf_init(sp7, 0);
-       sp7 = xmalloc(sizeof(struct strbuf));
-
-       use_before(&sb3);
-       use_as_str("%s", sb7.buf);
-       use_as_str("%s", sp1->buf);
-       use_as_str("%s", sp6->buf);
-       pass_pp(&sp3);
-
-       strbuf_release(&sb1);
-       strbuf_reset(&sb2);
-       strbuf_release(&sb3);
-       strbuf_release(&sb4);
-       strbuf_release(&sb5);
-       strbuf_release(&sb6);
-       strbuf_release(&sb7);
-       strbuf_release(sp1);
-       strbuf_release(sp2);
-       strbuf_release(sp3);
-       strbuf_release(sp4);
-       strbuf_release(sp5);
-       strbuf_release(sp6);
-       strbuf_release(sp7);
-
-       use_after(&sb4);
-
-       if (when_strict())
-               return;
-       strbuf_release(&sb8);
-}
-
-void test_other(void)
-{
-       struct string_list l = STRING_LIST_INIT_DUP;
-       struct strbuf sb = STRBUF_INIT;
-
-       string_list_clear(&l, 0);
-       string_list_clear(&sb, 0);
-}
-
-void test_worktrees(void)
-{
-       struct worktree **w1 = get_worktrees();
-       struct worktree **w2 = get_worktrees();
-       struct worktree **w3;
-       struct worktree **w4;
-
-       w3 = get_worktrees();
-       w4 = get_worktrees();
-
-       use_it(w4);
-
-       free_worktrees(w1);
-       free_worktrees(w2);
-       free_worktrees(w3);
-       free_worktrees(w4);
-}
diff --git a/contrib/coccinelle/tests/unused.res b/contrib/coccinelle/tests/unused.res
deleted file mode 100644 (file)
index 6d3e745..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-void test_strbuf(void)
-{
-       struct strbuf sb3 = STRBUF_INIT;
-       struct strbuf sb4 = STRBUF_INIT;
-       struct strbuf sb7 = STRBUF_INIT;
-       struct strbuf *sp1;
-       struct strbuf *sp3;
-       struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
-       strbuf_init(sp1, 0);
-       strbuf_init(sp3, 0);
-       strbuf_init(sp6, 0);
-
-       use_before(&sb3);
-       use_as_str("%s", sb7.buf);
-       use_as_str("%s", sp1->buf);
-       use_as_str("%s", sp6->buf);
-       pass_pp(&sp3);
-
-       strbuf_release(&sb3);
-       strbuf_release(&sb4);
-       strbuf_release(&sb7);
-       strbuf_release(sp1);
-       strbuf_release(sp3);
-       strbuf_release(sp6);
-
-       use_after(&sb4);
-
-       if (when_strict())
-               return;
-}
-
-void test_other(void)
-{
-}
-
-void test_worktrees(void)
-{
-       struct worktree **w4;
-
-       w4 = get_worktrees();
-
-       use_it(w4);
-
-       free_worktrees(w4);
-}
diff --git a/contrib/coccinelle/the_repository.cocci b/contrib/coccinelle/the_repository.cocci
new file mode 100644 (file)
index 0000000..765ad68
--- /dev/null
@@ -0,0 +1,123 @@
+// Fully migrated "the_repository" additions
+@@
+@@
+(
+// cache.h
+- get_oid
++ repo_get_oid
+|
+- get_oid_commit
++ repo_get_oid_commit
+|
+- get_oid_committish
++ repo_get_oid_committish
+|
+- get_oid_tree
++ repo_get_oid_tree
+|
+- get_oid_treeish
++ repo_get_oid_treeish
+|
+- get_oid_blob
++ repo_get_oid_blob
+|
+- get_oid_mb
++ repo_get_oid_mb
+|
+- find_unique_abbrev
++ repo_find_unique_abbrev
+|
+- find_unique_abbrev_r
++ repo_find_unique_abbrev_r
+|
+- for_each_abbrev
++ repo_for_each_abbrev
+|
+- interpret_branch_name
++ repo_interpret_branch_name
+|
+- peel_to_type
++ repo_peel_to_type
+// commit-reach.h
+|
+- get_merge_bases
++ repo_get_merge_bases
+|
+- get_merge_bases_many
++ repo_get_merge_bases_many
+|
+- get_merge_bases_many_dirty
++ repo_get_merge_bases_many_dirty
+|
+- in_merge_bases
++ repo_in_merge_bases
+|
+- in_merge_bases_many
++ repo_in_merge_bases_many
+// commit.h
+|
+- parse_commit_internal
++ repo_parse_commit_internal
+|
+- parse_commit
++ repo_parse_commit
+|
+- get_commit_buffer
++ repo_get_commit_buffer
+|
+- unuse_commit_buffer
++ repo_unuse_commit_buffer
+|
+- logmsg_reencode
++ repo_logmsg_reencode
+|
+- get_commit_tree
++ repo_get_commit_tree
+// diff.h
+|
+- diff_setup
++ repo_diff_setup
+// object-store.h
+|
+- read_object_file
++ repo_read_object_file
+|
+- has_object_file
++ repo_has_object_file
+|
+- has_object_file_with_flags
++ repo_has_object_file_with_flags
+// pretty.h
+|
+- format_commit_message
++ repo_format_commit_message
+// packfile.h
+|
+- approximate_object_count
++ repo_approximate_object_count
+// promisor-remote.h
+|
+- promisor_remote_reinit
++ repo_promisor_remote_reinit
+|
+- promisor_remote_find
++ repo_promisor_remote_find
+|
+- has_promisor_remote
++ repo_has_promisor_remote
+// refs.h
+|
+- dwim_ref
++ repo_dwim_ref
+// rerere.h
+|
+- rerere
++ repo_rerere
+// revision.h
+|
+- init_revisions
++ repo_init_revisions
+)
+  (
++ the_repository,
+  ...)
diff --git a/contrib/coccinelle/the_repository.pending.cocci b/contrib/coccinelle/the_repository.pending.cocci
deleted file mode 100644 (file)
index 747d382..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-// This file is used for the ongoing refactoring of
-// bringing the index or repository struct in all of
-// our code base.
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- read_object_file(
-+ repo_read_object_file(the_repository,
-  E, F, G)
-
-@@
-expression E;
-@@
-- has_object_file(
-+ repo_has_object_file(the_repository,
-  E)
-
-@@
-expression E;
-@@
-- has_object_file_with_flags(
-+ repo_has_object_file_with_flags(the_repository,
-  E)
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- parse_commit_internal(
-+ repo_parse_commit_internal(the_repository,
-  E, F, G)
-
-@@
-expression E;
-expression F;
-@@
-- parse_commit_gently(
-+ repo_parse_commit_gently(the_repository,
-  E, F)
-
-@@
-expression E;
-@@
-- parse_commit(
-+ repo_parse_commit(the_repository,
-  E)
-
-@@
-expression E;
-expression F;
-@@
-- get_merge_bases(
-+ repo_get_merge_bases(the_repository,
-  E, F);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- get_merge_bases_many(
-+ repo_get_merge_bases_many(the_repository,
-  E, F, G);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- get_merge_bases_many_dirty(
-+ repo_get_merge_bases_many_dirty(the_repository,
-  E, F, G);
-
-@@
-expression E;
-expression F;
-@@
-- in_merge_bases(
-+ repo_in_merge_bases(the_repository,
-  E, F);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- in_merge_bases_many(
-+ repo_in_merge_bases_many(the_repository,
-  E, F, G);
-
-@@
-expression E;
-expression F;
-@@
-- get_commit_buffer(
-+ repo_get_commit_buffer(the_repository,
-  E, F);
-
-@@
-expression E;
-expression F;
-@@
-- unuse_commit_buffer(
-+ repo_unuse_commit_buffer(the_repository,
-  E, F);
-
-@@
-expression E;
-expression F;
-expression G;
-@@
-- logmsg_reencode(
-+ repo_logmsg_reencode(the_repository,
-  E, F, G);
-
-@@
-expression E;
-expression F;
-expression G;
-expression H;
-@@
-- format_commit_message(
-+ repo_format_commit_message(the_repository,
-  E, F, G, H);
diff --git a/contrib/coccinelle/unused.cocci b/contrib/coccinelle/unused.cocci
deleted file mode 100644 (file)
index d84046f..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// This rule finds sequences of "unused" declerations and uses of a
-// variable, where "unused" is defined to include only calling the
-// equivalent of alloc, init & free functions on the variable.
-@@
-type T;
-identifier I;
-// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring)
-constant INIT_MACRO =~ "_INIT";
-identifier MALLOC1 =~ "^x?[mc]alloc$";
-identifier INIT_ASSIGN1 =~ "^get_worktrees$";
-identifier INIT_CALL1 =~ "^[a-z_]*_init$";
-identifier REL1 =~ "^[a-z_]*_(release|reset|clear|free)$";
-identifier REL2 =~ "^(release|clear|free)_[a-z_]*$";
-@@
-
-(
-- T I;
-|
-- T I = { 0 };
-|
-- T I = INIT_MACRO;
-|
-- T I = MALLOC1(...);
-|
-- T I = INIT_ASSIGN1(...);
-)
-
-<... when != \( I \| &I \)
-(
-- \( INIT_CALL1 \)( \( I \| &I \), ...);
-|
-- I = \( INIT_ASSIGN1 \)(...);
-|
-- I = MALLOC1(...);
-)
-...>
-
-(
-- \( REL1 \| REL2 \)( \( I \| &I \), ...);
-|
-- \( REL1 \| REL2 \)( \( &I \| I \) );
-)
-  ... when != \( I \| &I \)
index dc95c34cc853557efd2a59a33825f834e8d934cf..55950057c8debd6519282ba98db1c8fa678dc4a3 100644 (file)
@@ -28,6 +28,7 @@
 # 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 ; ... '".
+# Be sure to add a space between the command name and the ';'.
 #
 # If you have a command that is not part of git, but you would still
 # like completion, you can use __git_complete:
@@ -767,7 +768,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
@@ -1607,7 +1608,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"
@@ -1733,32 +1734,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 +1795,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 +2041,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 --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 +2095,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 +2129,6 @@ _git_log ()
                        --expand-tabs --expand-tabs= --no-expand-tabs
                        $merge
                        $__git_diff_common_options
-                       --pickaxe-all --pickaxe-regex
                        "
                return
                ;;
@@ -2484,7 +2515,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 +3023,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 57972c2845c135dc45aeb560d289aade4caa5e5d..2c030050aea1c67472570a9d86d69d55e31e7714 100644 (file)
 #
 # If you would like a colored hint about the current dirty state, set
 # GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
-# the colored output of "git status -sb" and are available only when
-# using __git_ps1 for PROMPT_COMMAND or precmd in Bash,
-# but always available in Zsh.
+# the colored output of "git status -sb".
 #
 # If you would like __git_ps1 to do nothing in the case when the current
 # directory is set up to be ignored by git, then set
@@ -259,12 +257,12 @@ __git_ps1_colorize_gitstring ()
                local c_lblue='%F{blue}'
                local c_clear='%f'
        else
-               # Using \[ and \] around colors is necessary to prevent
+               # Using \001 and \002 around colors is necessary to prevent
                # issues with command line editing/browsing/completion!
-               local c_red='\[\e[31m\]'
-               local c_green='\[\e[32m\]'
-               local c_lblue='\[\e[1;34m\]'
-               local c_clear='\[\e[0m\]'
+               local c_red=$'\001\e[31m\002'
+               local c_green=$'\001\e[32m\002'
+               local c_lblue=$'\001\e[1;34m\002'
+               local c_clear=$'\001\e[0m\002'
        fi
        local bad_color=$c_red
        local ok_color=$c_green
@@ -300,7 +298,7 @@ __git_ps1_colorize_gitstring ()
 # variable, in that order.
 __git_eread ()
 {
-       test -r "$1" && IFS=$'\r\n' read "$2" <"$1"
+       test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
 }
 
 # see if a cherry-pick or revert is in progress, if the user has committed a
@@ -574,11 +572,8 @@ __git_ps1 ()
                b="\${__git_ps1_branch_name}"
        fi
 
-       # NO color option unless in PROMPT_COMMAND mode or it's Zsh
        if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
-               if [ $pcmode = yes ] || [ -n "${ZSH_VERSION-}" ]; then
-                       __git_ps1_colorize_gitstring
-               fi
+               __git_ps1_colorize_gitstring
        fi
 
        local f="$h$w$i$s$u$p"
diff --git a/contrib/credential/gnome-keyring/.gitignore b/contrib/credential/gnome-keyring/.gitignore
deleted file mode 100644 (file)
index 88d8fcd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-git-credential-gnome-keyring
diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile
deleted file mode 100644 (file)
index 22c19df..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-MAIN:=git-credential-gnome-keyring
-all:: $(MAIN)
-
-CC = gcc
-RM = rm -f
-CFLAGS = -g -O2 -Wall
-PKG_CONFIG = pkg-config
-
--include ../../../config.mak.autogen
--include ../../../config.mak
-
-INCS:=$(shell $(PKG_CONFIG) --cflags gnome-keyring-1 glib-2.0)
-LIBS:=$(shell $(PKG_CONFIG) --libs gnome-keyring-1 glib-2.0)
-
-SRCS:=$(MAIN).c
-OBJS:=$(SRCS:.c=.o)
-
-%.o: %.c
-       $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $<
-
-$(MAIN): $(OBJS)
-       $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
-
-clean:
-       @$(RM) $(MAIN) $(OBJS)
diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
deleted file mode 100644 (file)
index 5927e27..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2011 John Szakmeister <john@szakmeister.net>
- *               2012 Philipp A. Hartmann <pah@qo.cx>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Credits:
- * - GNOME Keyring API handling originally written by John Szakmeister
- * - ported to credential helper API by Philipp A. Hartmann
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <gnome-keyring.h>
-
-#ifdef GNOME_KEYRING_DEFAULT
-
-   /* Modern gnome-keyring */
-
-#include <gnome-keyring-memory.h>
-
-#else
-
-   /*
-    * Support ancient gnome-keyring, circ. RHEL 5.X.
-    * GNOME_KEYRING_DEFAULT seems to have been introduced with Gnome 2.22,
-    * and the other features roughly around Gnome 2.20, 6 months before.
-    * Ubuntu 8.04 used Gnome 2.22 (I think).  Not sure any distro used 2.20.
-    * So the existence/non-existence of GNOME_KEYRING_DEFAULT seems like
-    * a decent thing to use as an indicator.
-    */
-
-#define GNOME_KEYRING_DEFAULT NULL
-
-/*
- * ancient gnome-keyring returns DENIED when an entry is not found.
- * Setting NO_MATCH to DENIED will prevent us from reporting DENIED
- * errors during get and erase operations, but we will still report
- * DENIED errors during a store.
- */
-#define GNOME_KEYRING_RESULT_NO_MATCH GNOME_KEYRING_RESULT_DENIED
-
-#define gnome_keyring_memory_alloc g_malloc
-#define gnome_keyring_memory_free gnome_keyring_free_password
-#define gnome_keyring_memory_strdup g_strdup
-
-static const char *gnome_keyring_result_to_message(GnomeKeyringResult result)
-{
-       switch (result) {
-       case GNOME_KEYRING_RESULT_OK:
-               return "OK";
-       case GNOME_KEYRING_RESULT_DENIED:
-               return "Denied";
-       case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON:
-               return "No Keyring Daemon";
-       case GNOME_KEYRING_RESULT_ALREADY_UNLOCKED:
-               return "Already UnLocked";
-       case GNOME_KEYRING_RESULT_NO_SUCH_KEYRING:
-               return "No Such Keyring";
-       case GNOME_KEYRING_RESULT_BAD_ARGUMENTS:
-               return "Bad Arguments";
-       case GNOME_KEYRING_RESULT_IO_ERROR:
-               return "IO Error";
-       case GNOME_KEYRING_RESULT_CANCELLED:
-               return "Cancelled";
-       case GNOME_KEYRING_RESULT_ALREADY_EXISTS:
-               return "Already Exists";
-       default:
-               return "Unknown Error";
-       }
-}
-
-/*
- * Support really ancient gnome-keyring, circ. RHEL 4.X.
- * Just a guess for the Glib version.  Glib 2.8 was roughly Gnome 2.12 ?
- * Which was released with gnome-keyring 0.4.3 ??
- */
-#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 8
-
-static void gnome_keyring_done_cb(GnomeKeyringResult result, gpointer user_data)
-{
-       gpointer *data = (gpointer *)user_data;
-       int *done = (int *)data[0];
-       GnomeKeyringResult *r = (GnomeKeyringResult *)data[1];
-
-       *r = result;
-       *done = 1;
-}
-
-static void wait_for_request_completion(int *done)
-{
-       GMainContext *mc = g_main_context_default();
-       while (!*done)
-               g_main_context_iteration(mc, TRUE);
-}
-
-static GnomeKeyringResult gnome_keyring_item_delete_sync(const char *keyring, guint32 id)
-{
-       int done = 0;
-       GnomeKeyringResult result;
-       gpointer data[] = { &done, &result };
-
-       gnome_keyring_item_delete(keyring, id, gnome_keyring_done_cb, data,
-               NULL);
-
-       wait_for_request_completion(&done);
-
-       return result;
-}
-
-#endif
-#endif
-
-/*
- * This credential struct and API is simplified from git's credential.{h,c}
- */
-struct credential {
-       char *protocol;
-       char *host;
-       unsigned short port;
-       char *path;
-       char *username;
-       char *password;
-};
-
-#define CREDENTIAL_INIT { 0 }
-
-typedef int (*credential_op_cb)(struct credential *);
-
-struct credential_operation {
-       char *name;
-       credential_op_cb op;
-};
-
-#define CREDENTIAL_OP_END { NULL, NULL }
-
-/* ----------------- GNOME Keyring functions ----------------- */
-
-/* create a special keyring option string, if path is given */
-static char *keyring_object(struct credential *c)
-{
-       if (!c->path)
-               return NULL;
-
-       if (c->port)
-               return g_strdup_printf("%s:%hd/%s", c->host, c->port, c->path);
-
-       return g_strdup_printf("%s/%s", c->host, c->path);
-}
-
-static int keyring_get(struct credential *c)
-{
-       char *object = NULL;
-       GList *entries;
-       GnomeKeyringNetworkPasswordData *password_data;
-       GnomeKeyringResult result;
-
-       if (!c->protocol || !(c->host || c->path))
-               return EXIT_FAILURE;
-
-       object = keyring_object(c);
-
-       result = gnome_keyring_find_network_password_sync(
-                               c->username,
-                               NULL /* domain */,
-                               c->host,
-                               object,
-                               c->protocol,
-                               NULL /* authtype */,
-                               c->port,
-                               &entries);
-
-       g_free(object);
-
-       if (result == GNOME_KEYRING_RESULT_NO_MATCH)
-               return EXIT_SUCCESS;
-
-       if (result == GNOME_KEYRING_RESULT_CANCELLED)
-               return EXIT_SUCCESS;
-
-       if (result != GNOME_KEYRING_RESULT_OK) {
-               g_critical("%s", gnome_keyring_result_to_message(result));
-               return EXIT_FAILURE;
-       }
-
-       /* pick the first one from the list */
-       password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
-
-       gnome_keyring_memory_free(c->password);
-       c->password = gnome_keyring_memory_strdup(password_data->password);
-
-       if (!c->username)
-               c->username = g_strdup(password_data->user);
-
-       gnome_keyring_network_password_list_free(entries);
-
-       return EXIT_SUCCESS;
-}
-
-
-static int keyring_store(struct credential *c)
-{
-       guint32 item_id;
-       char *object = NULL;
-       GnomeKeyringResult result;
-
-       /*
-        * Sanity check that what we are storing is actually sensible.
-        * In particular, we can't make a URL without a protocol field.
-        * Without either a host or pathname (depending on the scheme),
-        * we have no primary key. And without a username and password,
-        * we are not actually storing a credential.
-        */
-       if (!c->protocol || !(c->host || c->path) ||
-           !c->username || !c->password)
-               return EXIT_FAILURE;
-
-       object = keyring_object(c);
-
-       result = gnome_keyring_set_network_password_sync(
-                               GNOME_KEYRING_DEFAULT,
-                               c->username,
-                               NULL /* domain */,
-                               c->host,
-                               object,
-                               c->protocol,
-                               NULL /* authtype */,
-                               c->port,
-                               c->password,
-                               &item_id);
-
-       g_free(object);
-
-       if (result != GNOME_KEYRING_RESULT_OK &&
-           result != GNOME_KEYRING_RESULT_CANCELLED) {
-               g_critical("%s", gnome_keyring_result_to_message(result));
-               return EXIT_FAILURE;
-       }
-
-       return EXIT_SUCCESS;
-}
-
-static int keyring_erase(struct credential *c)
-{
-       char *object = NULL;
-       GList *entries;
-       GnomeKeyringNetworkPasswordData *password_data;
-       GnomeKeyringResult result;
-
-       /*
-        * Sanity check that we actually have something to match
-        * against. The input we get is a restrictive pattern,
-        * so technically a blank credential means "erase everything".
-        * But it is too easy to accidentally send this, since it is equivalent
-        * to empty input. So explicitly disallow it, and require that the
-        * pattern have some actual content to match.
-        */
-       if (!c->protocol && !c->host && !c->path && !c->username)
-               return EXIT_FAILURE;
-
-       object = keyring_object(c);
-
-       result = gnome_keyring_find_network_password_sync(
-                               c->username,
-                               NULL /* domain */,
-                               c->host,
-                               object,
-                               c->protocol,
-                               NULL /* authtype */,
-                               c->port,
-                               &entries);
-
-       g_free(object);
-
-       if (result == GNOME_KEYRING_RESULT_NO_MATCH)
-               return EXIT_SUCCESS;
-
-       if (result == GNOME_KEYRING_RESULT_CANCELLED)
-               return EXIT_SUCCESS;
-
-       if (result != GNOME_KEYRING_RESULT_OK) {
-               g_critical("%s", gnome_keyring_result_to_message(result));
-               return EXIT_FAILURE;
-       }
-
-       /* pick the first one from the list (delete all matches?) */
-       password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
-
-       result = gnome_keyring_item_delete_sync(
-               password_data->keyring, password_data->item_id);
-
-       gnome_keyring_network_password_list_free(entries);
-
-       if (result != GNOME_KEYRING_RESULT_OK) {
-               g_critical("%s", gnome_keyring_result_to_message(result));
-               return EXIT_FAILURE;
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/*
- * Table with helper operation callbacks, used by generic
- * credential helper main function.
- */
-static struct credential_operation const credential_helper_ops[] = {
-       { "get",   keyring_get },
-       { "store", keyring_store },
-       { "erase", keyring_erase },
-       CREDENTIAL_OP_END
-};
-
-/* ------------------ credential functions ------------------ */
-
-static void credential_init(struct credential *c)
-{
-       memset(c, 0, sizeof(*c));
-}
-
-static void credential_clear(struct credential *c)
-{
-       g_free(c->protocol);
-       g_free(c->host);
-       g_free(c->path);
-       g_free(c->username);
-       gnome_keyring_memory_free(c->password);
-
-       credential_init(c);
-}
-
-static int credential_read(struct credential *c)
-{
-       char *buf;
-       size_t line_len;
-       char *key;
-       char *value;
-
-       key = buf = gnome_keyring_memory_alloc(1024);
-
-       while (fgets(buf, 1024, stdin)) {
-               line_len = strlen(buf);
-
-               if (line_len && buf[line_len-1] == '\n')
-                       buf[--line_len] = '\0';
-
-               if (!line_len)
-                       break;
-
-               value = strchr(buf, '=');
-               if (!value) {
-                       g_warning("invalid credential line: %s", key);
-                       gnome_keyring_memory_free(buf);
-                       return -1;
-               }
-               *value++ = '\0';
-
-               if (!strcmp(key, "protocol")) {
-                       g_free(c->protocol);
-                       c->protocol = g_strdup(value);
-               } else if (!strcmp(key, "host")) {
-                       g_free(c->host);
-                       c->host = g_strdup(value);
-                       value = strrchr(c->host, ':');
-                       if (value) {
-                               *value++ = '\0';
-                               c->port = atoi(value);
-                       }
-               } else if (!strcmp(key, "path")) {
-                       g_free(c->path);
-                       c->path = g_strdup(value);
-               } else if (!strcmp(key, "username")) {
-                       g_free(c->username);
-                       c->username = g_strdup(value);
-               } else if (!strcmp(key, "password")) {
-                       gnome_keyring_memory_free(c->password);
-                       c->password = gnome_keyring_memory_strdup(value);
-                       while (*value)
-                               *value++ = '\0';
-               }
-               /*
-                * Ignore other lines; we don't know what they mean, but
-                * this future-proofs us when later versions of git do
-                * learn new lines, and the helpers are updated to match.
-                */
-       }
-
-       gnome_keyring_memory_free(buf);
-
-       return 0;
-}
-
-static void credential_write_item(FILE *fp, const char *key, const char *value)
-{
-       if (!value)
-               return;
-       fprintf(fp, "%s=%s\n", key, value);
-}
-
-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);
-}
-
-static void usage(const char *name)
-{
-       struct credential_operation const *try_op = credential_helper_ops;
-       const char *basename = strrchr(name, '/');
-
-       basename = (basename) ? basename + 1 : name;
-       fprintf(stderr, "usage: %s <", basename);
-       while (try_op->name) {
-               fprintf(stderr, "%s", (try_op++)->name);
-               if (try_op->name)
-                       fprintf(stderr, "%s", "|");
-       }
-       fprintf(stderr, "%s", ">\n");
-}
-
-int main(int argc, char *argv[])
-{
-       int ret = EXIT_SUCCESS;
-
-       struct credential_operation const *try_op = credential_helper_ops;
-       struct credential cred = CREDENTIAL_INIT;
-
-       if (!argv[1]) {
-               usage(argv[0]);
-               exit(EXIT_FAILURE);
-       }
-
-       g_set_application_name("Git Credential Helper");
-
-       /* lookup operation callback */
-       while (try_op->name && strcmp(argv[1], try_op->name))
-               try_op++;
-
-       /* unsupported operation given -- ignore silently */
-       if (!try_op->name || !try_op->op)
-               goto out;
-
-       ret = credential_read(&cred);
-       if (ret)
-               goto out;
-
-       /* perform credential operation */
-       ret = (*try_op->op)(&cred);
-
-       credential_write(&cred);
-
-out:
-       credential_clear(&cred);
-       return ret;
-}
diff --git a/contrib/credential/libsecret/.gitignore b/contrib/credential/libsecret/.gitignore
new file mode 100644 (file)
index 0000000..4fa2235
--- /dev/null
@@ -0,0 +1 @@
+git-credential-libsecret
index 2c5d76d789f0fabbdcd30d2684a4021b647731db..ef681f29d5ba12dd5c6f7f11baa42cb1e6aab7d5 100644 (file)
@@ -244,17 +244,16 @@ static void credential_clear(struct credential *c)
 
 static int credential_read(struct credential *c)
 {
-       char *buf;
-       size_t line_len;
+       char *buf = NULL;
+       size_t alloc;
+       ssize_t line_len;
        char *key;
        char *value;
 
-       key = buf = g_malloc(1024);
+       while ((line_len = getline(&buf, &alloc, stdin)) > 0) {
+               key = buf;
 
-       while (fgets(buf, 1024, stdin)) {
-               line_len = strlen(buf);
-
-               if (line_len && buf[line_len-1] == '\n')
+               if (buf[line_len-1] == '\n')
                        buf[--line_len] = '\0';
 
                if (!line_len)
@@ -298,7 +297,7 @@ static int credential_read(struct credential *c)
                 */
        }
 
-       g_free(buf);
+       free(buf);
 
        return 0;
 }
index e29cc28779dbb846de8446d4dce3a86dfe0ece5f..5f2e5f16c889ff278bc51553816c54acb41be21e 100644 (file)
@@ -113,14 +113,16 @@ static void add_internet_password(void)
 
 static void read_credential(void)
 {
-       char buf[1024];
+       char *buf = NULL;
+       size_t alloc;
+       ssize_t line_len;
 
-       while (fgets(buf, sizeof(buf), stdin)) {
+       while ((line_len = getline(&buf, &alloc, stdin)) > 0) {
                char *v;
 
                if (!strcmp(buf, "\n"))
                        break;
-               buf[strlen(buf)-1] = '\0';
+               buf[line_len-1] = '\0';
 
                v = strchr(buf, '=');
                if (!v)
@@ -165,6 +167,8 @@ static void read_credential(void)
                 * learn new lines, and the helpers are updated to match.
                 */
        }
+
+       free(buf);
 }
 
 int main(int argc, const char **argv)
index ead6e267c78120f06bfd2e74def8bbe2f4b66e50..96f10613aee29b7c360b25308927564df1551388 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdio.h>
 #include <io.h>
 #include <fcntl.h>
+#include <wincred.h>
 
 /* common helpers */
 
@@ -33,65 +34,8 @@ static void *xmalloc(size_t size)
        return ret;
 }
 
-/* MinGW doesn't have wincred.h, so we need to define stuff */
-
-typedef struct _CREDENTIAL_ATTRIBUTEW {
-       LPWSTR Keyword;
-       DWORD  Flags;
-       DWORD  ValueSize;
-       LPBYTE Value;
-} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;
-
-typedef struct _CREDENTIALW {
-       DWORD                  Flags;
-       DWORD                  Type;
-       LPWSTR                 TargetName;
-       LPWSTR                 Comment;
-       FILETIME               LastWritten;
-       DWORD                  CredentialBlobSize;
-       LPBYTE                 CredentialBlob;
-       DWORD                  Persist;
-       DWORD                  AttributeCount;
-       PCREDENTIAL_ATTRIBUTEW Attributes;
-       LPWSTR                 TargetAlias;
-       LPWSTR                 UserName;
-} CREDENTIALW, *PCREDENTIALW;
-
-#define CRED_TYPE_GENERIC 1
-#define CRED_PERSIST_LOCAL_MACHINE 2
-#define CRED_MAX_ATTRIBUTES 64
-
-typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
-typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
-    PCREDENTIALW **);
-typedef VOID (WINAPI *CredFreeT)(PVOID);
-typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
-
-static HMODULE advapi;
-static CredWriteWT CredWriteW;
-static CredEnumerateWT CredEnumerateW;
-static CredFreeT CredFree;
-static CredDeleteWT CredDeleteW;
-
-static void load_cred_funcs(void)
-{
-       /* load DLLs */
-       advapi = LoadLibraryExA("advapi32.dll", NULL,
-                               LOAD_LIBRARY_SEARCH_SYSTEM32);
-       if (!advapi)
-               die("failed to load advapi32.dll");
-
-       /* get function pointers */
-       CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
-       CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
-           "CredEnumerateW");
-       CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
-       CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
-       if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW)
-               die("failed to load functions");
-}
-
-static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
+static WCHAR *wusername, *password, *protocol, *host, *path, target[1024],
+       *password_expiry_utc;
 
 static void write_item(const char *what, LPCWSTR wbuf, int wlen)
 {
@@ -183,6 +127,7 @@ static void get_credential(void)
        CREDENTIALW **creds;
        DWORD num_creds;
        int i;
+       CREDENTIAL_ATTRIBUTEW *attr;
 
        if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
                return;
@@ -195,6 +140,14 @@ static void get_credential(void)
                        write_item("password",
                                (LPCWSTR)creds[i]->CredentialBlob,
                                creds[i]->CredentialBlobSize / sizeof(WCHAR));
+                       for (int j = 0; j < creds[i]->AttributeCount; j++) {
+                               attr = creds[i]->Attributes + j;
+                               if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) {
+                                       write_item("password_expiry_utc", (LPCWSTR)attr->Value,
+                                       attr->ValueSize / sizeof(WCHAR));
+                                       break;
+                               }
+                       }
                        break;
                }
 
@@ -204,6 +157,7 @@ static void get_credential(void)
 static void store_credential(void)
 {
        CREDENTIALW cred;
+       CREDENTIAL_ATTRIBUTEW expiry_attr;
 
        if (!wusername || !password)
                return;
@@ -217,6 +171,14 @@ static void store_credential(void)
        cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
        cred.AttributeCount = 0;
        cred.Attributes = NULL;
+       if (password_expiry_utc != NULL) {
+               expiry_attr.Keyword = L"git_password_expiry_utc";
+               expiry_attr.Value = (LPVOID)password_expiry_utc;
+               expiry_attr.ValueSize = (wcslen(password_expiry_utc)) * sizeof(WCHAR);
+               expiry_attr.Flags = 0;
+               cred.Attributes = &expiry_attr;
+               cred.AttributeCount = 1;
+       }
        cred.TargetAlias = NULL;
        cred.UserName = wusername;
 
@@ -249,17 +211,28 @@ static WCHAR *utf8_to_utf16_dup(const char *str)
        return wstr;
 }
 
+#define KB (1024)
+
 static void read_credential(void)
 {
-       char buf[1024];
+       size_t alloc = 100 * KB;
+       char *buf = calloc(alloc, sizeof(*buf));
 
-       while (fgets(buf, sizeof(buf), stdin)) {
+       while (fgets(buf, alloc, stdin)) {
                char *v;
-               int len = strlen(buf);
+               size_t len = strlen(buf);
+               int ends_in_newline = 0;
                /* strip trailing CR / LF */
-               while (len && strchr("\r\n", buf[len - 1]))
+               if (len && buf[len - 1] == '\n') {
+                       buf[--len] = 0;
+                       ends_in_newline = 1;
+               }
+               if (len && buf[len - 1] == '\r')
                        buf[--len] = 0;
 
+               if (!ends_in_newline)
+                       die("bad input: %s", buf);
+
                if (!*buf)
                        break;
 
@@ -278,12 +251,16 @@ static void read_credential(void)
                        wusername = utf8_to_utf16_dup(v);
                } else if (!strcmp(buf, "password"))
                        password = utf8_to_utf16_dup(v);
+               else if (!strcmp(buf, "password_expiry_utc"))
+                       password_expiry_utc = utf8_to_utf16_dup(v);
                /*
                 * Ignore other lines; we don't know what they mean, but
                 * this future-proofs us when later versions of git do
                 * learn new lines, and the helpers are updated to match.
                 */
        }
+
+       free(buf);
 }
 
 int main(int argc, char *argv[])
@@ -292,7 +269,7 @@ int main(int argc, char *argv[])
            "usage: git credential-wincred <get|store|erase>\n";
 
        if (!argv[1])
-               die(usage);
+               die("%s", usage);
 
        /* git use binary pipes to avoid CRLF-issues */
        _setmode(_fileno(stdin), _O_BINARY);
@@ -300,8 +277,6 @@ int main(int argc, char *argv[])
 
        read_credential();
 
-       load_cred_funcs();
-
        if (!protocol || !(host || path))
                return 0;
 
index 10c9c87839a4cf4e78fe8f270eac18d9942b783c..7db4c45676d304869bba126bd57e7f553aec2008 100755 (executable)
@@ -34,8 +34,8 @@ git subtree pull  --prefix=<prefix> <repository> <ref>
 git subtree push  --prefix=<prefix> <repository> <refspec>
 --
 h,help        show the help
-q             quiet
-d             show debug messages
+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
index 4655e0987b32a837e966832eaebf89ed3ea829e9..093399c788178f3d4f005fc9d580e7c030e2d40a 100644 (file)
@@ -74,9 +74,7 @@ aggregate-results-and-cleanup: $(T)
        $(MAKE) clean
 
 aggregate-results:
-       for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \
-               echo "$$f"; \
-       done | '$(SHELL_PATH_SQ)' ../../../t/aggregate-results.sh
+       @'$(SHELL_PATH_SQ)' ../../../t/aggregate-results.sh '$(TEST_RESULTS_DIRECTORY_SQ)'
 
 valgrind:
        $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
index a54d1690c083178fd0c1356c8c8c8bee5cfdbda1..a8870baff36a4a3042baf31c730793b45f6b6442 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1,14 +1,21 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "config.h"
-#include "object-store.h"
+#include "convert.h"
+#include "copy.h"
+#include "gettext.h"
+#include "hex.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 "merge-ll.h"
 
 /*
  * convert.c - convert a file when checking it out and checking it in.
@@ -626,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;
@@ -1008,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;
@@ -1308,7 +1315,7 @@ void convert_attrs(struct index_state *istate,
                git_config(read_convert_config, NULL);
        }
 
-       git_check_attr(istate, NULL, path, check);
+       git_check_attr(istate, path, check);
        ccheck = check->items;
        ca->crlf_action = git_path_check_crlf(ccheck + 4);
        if (ca->crlf_action == CRLF_UNDEFINED)
index 0a6e4086b8f93257df513a20a4cc55062d218212..d925589444b90a11058abe87286df3d5add592f8 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -4,7 +4,7 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
-#include "hash.h"
+#include "hash-ll.h"
 #include "string-list.h"
 
 struct index_state;
diff --git a/copy.c b/copy.c
index 4de6a110f0912d81def3f2dd4ffd6ddc9bc30d2f..23d84c6c1db554bcc7a33804d58821dfb3fb7634 100644 (file)
--- a/copy.c
+++ b/copy.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "copy.h"
+#include "path.h"
 
 int copy_fd(int ifd, int ofd)
 {
diff --git a/copy.h b/copy.h
new file mode 100644 (file)
index 0000000..2af77cb
--- /dev/null
+++ b/copy.h
@@ -0,0 +1,10 @@
+#ifndef COPY_H
+#define COPY_H
+
+#define COPY_READ_ERROR (-2)
+#define COPY_WRITE_ERROR (-3)
+int copy_fd(int ifd, int ofd);
+int copy_file(const char *dst, const char *src, int mode);
+int copy_file_with_time(const char *dst, const char *src, int mode);
+
+#endif /* COPY_H */
index f32011343f9400a80cb9999fe75e0eeefde48146..d6647541634f3850ea147cebc681a5944d8e5ee9 100644 (file)
@@ -1,11 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
 #include "credential.h"
+#include "gettext.h"
 #include "string-list.h"
 #include "run-command.h"
 #include "url.h"
 #include "prompt.h"
 #include "sigchain.h"
+#include "strbuf.h"
 #include "urlmatch.h"
 #include "git-compat-util.h"
 
@@ -22,19 +25,22 @@ void credential_clear(struct credential *c)
        free(c->path);
        free(c->username);
        free(c->password);
+       free(c->oauth_refresh_token);
        string_list_clear(&c->helpers, 0);
+       strvec_clear(&c->wwwauth_headers);
 
        credential_init(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
 }
 
@@ -43,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;
@@ -97,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;
@@ -235,11 +242,16 @@ int credential_read(struct credential *c, FILE *fp)
                } else if (!strcmp(key, "path")) {
                        free(c->path);
                        c->path = xstrdup(value);
+               } else if (!strcmp(key, "wwwauth[]")) {
+                       strvec_push(&c->wwwauth_headers, value);
                } else if (!strcmp(key, "password_expiry_utc")) {
                        errno = 0;
                        c->password_expiry_utc = parse_timestamp(value, NULL, 10);
                        if (c->password_expiry_utc == 0 || errno == ERANGE)
                                c->password_expiry_utc = TIME_MAX;
+               } else if (!strcmp(key, "oauth_refresh_token")) {
+                       free(c->oauth_refresh_token);
+                       c->oauth_refresh_token = xstrdup(value);
                } else if (!strcmp(key, "url")) {
                        credential_from_url(c, value);
                } else if (!strcmp(key, "quit")) {
@@ -275,11 +287,14 @@ void credential_write(const struct credential *c, FILE *fp)
        credential_write_item(fp, "path", c->path, 0);
        credential_write_item(fp, "username", c->username, 0);
        credential_write_item(fp, "password", c->password, 0);
+       credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
        if (c->password_expiry_utc != TIME_MAX) {
                char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
                credential_write_item(fp, "password_expiry_utc", s, 0);
                free(s);
        }
+       for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
+               credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
 }
 
 static int run_credential_helper(struct credential *c,
@@ -398,6 +413,7 @@ void credential_reject(struct credential *c)
 
        FREE_AND_NULL(c->username);
        FREE_AND_NULL(c->password);
+       FREE_AND_NULL(c->oauth_refresh_token);
        c->password_expiry_utc = TIME_MAX;
        c->approved = 0;
 }
index 935b28a70f16ec788e9df0126ccfb00fa86de7cd..acc41adf5481a21148a6b4797f9a8267feb5d8b6 100644 (file)
@@ -2,6 +2,7 @@
 #define CREDENTIAL_H
 
 #include "string-list.h"
+#include "strvec.h"
 
 /**
  * The credentials API provides an abstracted way of gathering username and
@@ -115,6 +116,20 @@ struct credential {
         */
        struct string_list helpers;
 
+       /**
+        * A `strvec` of WWW-Authenticate header values. Each string
+        * is the value of a WWW-Authenticate header in an HTTP response,
+        * in the order they were received in the response.
+        */
+       struct strvec wwwauth_headers;
+
+       /**
+        * Internal use only. Keeps track of if we previously matched against a
+        * WWW-Authenticate header line in order to re-fold future continuation
+        * lines into one value.
+        */
+       unsigned header_is_last_match:1;
+
        unsigned approved:1,
                 configured:1,
                 quit:1,
@@ -126,12 +141,14 @@ struct credential {
        char *protocol;
        char *host;
        char *path;
+       char *oauth_refresh_token;
        timestamp_t password_expiry_utc;
 };
 
 #define CREDENTIAL_INIT { \
        .helpers = STRING_LIST_INIT_DUP, \
        .password_expiry_utc = TIME_MAX, \
+       .wwwauth_headers = STRVEC_INIT, \
 }
 
 /* Initialize a credential structure, setting all fields to empty. */
@@ -194,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 cce13c0f0473183a201a15e86de256cfd7bfc7d9..cd017132448d1ec340f137d6b882ee9bc420509a 100644 (file)
@@ -7,9 +7,10 @@
  * files. Useful when you write a file that you want to be
  * able to verify hasn't been messed with afterwards.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "progress.h"
 #include "csum-file.h"
+#include "hash.h"
 
 static void verify_buffer_or_die(struct hashfile *f,
                                 const void *buf,
index 793a59da12b6e6bc23c0542e83f33dcfdc8509fe..bc5bec27acbab4a3303f4ea11575b0c1accda806 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef CSUM_FILE_H
 #define CSUM_FILE_H
 
-#include "cache.h"
-#include "hash.h"
+#include "hash-ll.h"
+#include "write-or-die.h"
 
 struct progress;
 
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 0ae7d12b5c132883907192d16c3e2f04d56a80fb..f5e597114b671fc79cd0acf63c63e5ac427af8bf 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1,7 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
+#include "environment.h"
+#include "path.h"
 #include "pkt-line.h"
+#include "protocol.h"
 #include "run-command.h"
+#include "setup.h"
 #include "strbuf.h"
 #include "string-list.h"
 
@@ -137,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];
@@ -216,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 */
@@ -227,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));
@@ -928,7 +910,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
                add_child(&cld, addr, addrlen);
 }
 
-static void child_handler(int signo)
+static void child_handler(int signo UNUSED)
 {
        /*
         * Otherwise empty handler because systemcalls will get interrupted
diff --git a/date.c b/date.c
index 6f45eeb3568671e5b4bb37c2830315a490a12cfe..619ada5b20442046ef50a38d4e88136b14419a42 100644 (file)
--- a/date.c
+++ b/date.c
@@ -4,8 +4,11 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "date.h"
+#include "gettext.h"
+#include "pager.h"
+#include "strbuf.h"
 
 /*
  * This is like mktime, but without normalization of tm_wday and tm_yday.
@@ -1365,20 +1368,6 @@ static timestamp_t approxidate_str(const char *date,
        return (timestamp_t)update_tm(&tm, &now, 0);
 }
 
-timestamp_t approxidate_relative(const char *date)
-{
-       struct timeval tv;
-       timestamp_t timestamp;
-       int offset;
-       int errors = 0;
-
-       if (!parse_date_basic(date, &timestamp, &offset))
-               return timestamp;
-
-       get_time(&tv);
-       return approxidate_str(date, (const struct timeval *) &tv, &errors);
-}
-
 timestamp_t approxidate_careful(const char *date, int *error_ret)
 {
        struct timeval tv;
diff --git a/date.h b/date.h
index 5d4eaba0a90e39f8684bb5500695ba07b5ea5521..6136212a19004497382e5bae8d6675ebaac62011 100644 (file)
--- a/date.h
+++ b/date.h
@@ -68,7 +68,6 @@ int parse_expiry_date(const char *date, timestamp_t *timestamp);
 void datestamp(struct strbuf *out);
 #define approxidate(s) approxidate_careful((s), NULL)
 timestamp_t approxidate_careful(const char *, int *);
-timestamp_t approxidate_relative(const char *date);
 int date_overflows(timestamp_t date);
 time_t tm_to_time_t(const struct tm *tm);
 #endif
index 2036d15967125303effff870a45066710ef99e3e..a5c43c0c1461761bb808b4d6b833222b181843a6 100644 (file)
@@ -2,7 +2,7 @@
  * decorate.c - decorate a git object with some arbitrary
  * data.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "object.h"
 #include "decorate.h"
 
index afdec0a878d9368b134342084442317e15007a9c..5de5759f3f13da13465ec6c9bfa6abeb44ceaee3 100644 (file)
@@ -1,8 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "attr.h"
 #include "object.h"
 #include "blob.h"
 #include "commit.h"
+#include "gettext.h"
+#include "hex.h"
 #include "tag.h"
 #include "tree.h"
 #include "delta.h"
@@ -338,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;
 
@@ -506,8 +510,9 @@ void propagate_island_marks(struct commit *commit)
                struct commit_list *p;
                struct island_bitmap *root_marks = kh_value(island_marks, pos);
 
-               parse_commit(commit);
-               set_island_marks(&get_commit_tree(commit)->object, root_marks);
+               repo_parse_commit(the_repository, commit);
+               set_island_marks(&repo_get_commit_tree(the_repository, commit)->object,
+                                root_marks);
                for (p = commit->parents; p; p = p->next)
                        set_island_marks(&p->item->object, root_marks);
        }
index 50087f567062c4ff858bd6cae83fb3c59a0e4038..a87650b71bb095d403993486a7f2af6967be4d55 100755 (executable)
@@ -17,7 +17,15 @@ get_family() {
 }
 
 get_version() {
-       get_version_line | sed 's/^.* version \([0-9][^ ]*\).*/\1/'
+       # A string that begins with a digit up to the next SP
+       ver=$(get_version_line | sed 's/^.* version \([0-9][^ ]*\).*/\1/')
+
+       # There are known -variant suffixes that do not affect the
+       # meaning of the main version number.  Strip them.
+       ver=${ver%-win32}
+       ver=${ver%-posix}
+
+       echo "$ver"
 }
 
 print_flags() {
index 8f2656989666b67a3281d29a83f73ff82a006a1d..8430064000bcba96506e4b9c99c9efe60ba072f4 100644 (file)
@@ -1,12 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "diagnose.h"
 #include "compat/disk.h"
 #include "archive.h"
 #include "dir.h"
 #include "help.h"
+#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"
 
 struct archive_dir {
        const char *path;
@@ -43,7 +47,8 @@ int option_parse_diagnose(const struct option *opt, const char *arg, int unset)
        return error(_("invalid --%s value '%s'"), opt->long_name, arg);
 }
 
-static void dir_file_stats_objects(const char *full_path, size_t full_path_len,
+static void dir_file_stats_objects(const char *full_path,
+                                  size_t full_path_len UNUSED,
                                   const char *file_name, void *data)
 {
        struct strbuf *buf = data;
index 7a4951a7863bcea8ac37e2d40d656b794f9bc925..f525219ab0cf9b36249892c847e731b952b081af 100644 (file)
@@ -2,7 +2,8 @@
 #define DIAGNOSE_H
 
 #include "strbuf.h"
-#include "parse-options.h"
+
+struct option;
 
 enum diagnose_mode {
        DIAGNOSE_NONE,
index dec040c366c82a71bc57bad9cf9db865182efe20..5848e4f9ca294052b0e06c7e4d038ebd462ade92 100644 (file)
@@ -1,16 +1,24 @@
 /*
  * 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"
 #include "dir.h"
 #include "fsmonitor.h"
 #include "commit-reach.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)) {
@@ -88,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;
@@ -141,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 {
@@ -221,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);
@@ -264,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;
 }
 
 /*
@@ -296,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) {
@@ -581,7 +588,7 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
        if (revs->pending.nr == 1) {
                struct object_id oid;
 
-               if (get_oid("HEAD", &oid))
+               if (repo_get_oid(the_repository, "HEAD", &oid))
                        die(_("unable to get HEAD"));
 
                mb_child[1] = lookup_commit_reference(the_repository, &oid);
@@ -598,7 +605,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);
@@ -632,7 +639,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)
@@ -664,10 +670,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 85cbefa5afd7c00e903232011ef3d2ff7aca4a8f..ec97616db1dfaa0673945bb08a9f364b2d570db1 100644 (file)
@@ -1,5 +1,7 @@
+#include "git-compat-util.h"
 #include "diff-merges.h"
 
+#include "gettext.h"
 #include "revision.h"
 
 typedef void (*diff_merges_setup_func_t)(struct rev_info *);
index 05fafd0019b6d5acc7295b999a8a46c92e1a649e..e7041b89e38887e04237a00f84366781dbabf739 100644 (file)
@@ -4,16 +4,17 @@
  * Copyright (c) 2008 by Junio C Hamano
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "color.h"
 #include "commit.h"
 #include "blob.h"
 #include "tag.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "gettext.h"
 #include "revision.h"
 #include "log-tree.h"
-#include "builtin.h"
 #include "parse-options.h"
 #include "string-list.h"
 #include "dir.h"
@@ -40,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;
 
@@ -83,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)) {
@@ -101,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;
                }
@@ -173,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);
@@ -187,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;
        }
@@ -215,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) {
@@ -295,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);
@@ -305,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 469e18aed20ed0128bfa85774cb617d455287eaa..bccb018da468480615c04d858909891ac59b69e5 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1,34 +1,47 @@
 /*
  * Copyright (C) 2005 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "base85.h"
 #include "config.h"
+#include "convert.h"
+#include "environment.h"
+#include "gettext.h"
 #include "tempfile.h"
 #include "quote.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "delta.h"
+#include "hex.h"
 #include "xdiff-interface.h"
 #include "color.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 "oid-array.h"
 #include "packfile.h"
+#include "pager.h"
 #include "parse-options.h"
 #include "help.h"
 #include "promisor-remote.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"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -127,7 +140,7 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
        int i;
 
        if (*params_copy)
-               string_list_split_in_place(&params, params_copy, ',', -1);
+               string_list_split_in_place(&params, params_copy, ",", -1);
        for (i = 0; i < params.nr; i++) {
                const char *p = params.items[i].string;
                if (!strcmp(p, "changes")) {
@@ -343,7 +356,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);
@@ -364,13 +378,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;
@@ -396,7 +411,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                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"))
@@ -426,15 +441,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;
        }
 
@@ -481,7 +497,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)
@@ -2993,6 +3009,24 @@ static int dirstat_compare(const void *_a, const void *_b)
        return strcmp(a->name, b->name);
 }
 
+static void conclude_dirstat(struct diff_options *options,
+                            struct dirstat_dir *dir,
+                            unsigned long changed)
+{
+       struct dirstat_file *to_free = dir->files;
+
+       if (!changed) {
+               /* This can happen even with many files, if everything was renames */
+               ;
+       } else {
+               /* Show all directories with more than x% of the changes */
+               QSORT(dir->files, dir->nr, dirstat_compare);
+               gather_dirstat(options, dir, changed, "", 0);
+       }
+
+       free(to_free);
+}
+
 static void show_dirstat(struct diff_options *options)
 {
        int i;
@@ -3082,13 +3116,7 @@ found_damage:
                dir.nr++;
        }
 
-       /* This can happen even with many files, if everything was renames */
-       if (!changed)
-               return;
-
-       /* Show all directories with more than x% of the changes */
-       QSORT(dir.files, dir.nr, dirstat_compare);
-       gather_dirstat(options, &dir, changed, "", 0);
+       conclude_dirstat(options, &dir, changed);
 }
 
 static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *options)
@@ -3126,13 +3154,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
                dir.nr++;
        }
 
-       /* This can happen even with many files, if everything was renames */
-       if (!changed)
-               return;
-
-       /* Show all directories with more than x% of the changes */
-       QSORT(dir.files, dir.nr, dirstat_compare);
-       gather_dirstat(options, &dir, changed, "", 0);
+       conclude_dirstat(options, &dir, changed);
 }
 
 static void free_diffstat_file(struct diffstat_file *f)
@@ -3374,6 +3396,17 @@ void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const
                options->b_prefix = b;
 }
 
+void diff_set_noprefix(struct diff_options *options)
+{
+       options->a_prefix = options->b_prefix = "";
+}
+
+void diff_set_default_prefix(struct diff_options *options)
+{
+       options->a_prefix = "a/";
+       options->b_prefix = "b/";
+}
+
 struct userdiff_driver *get_textconv(struct repository *r,
                                     struct diff_filespec *one)
 {
@@ -3530,18 +3563,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)
@@ -4351,7 +4387,7 @@ static int similarity_index(struct diff_filepair *p)
 static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
 {
        if (startup_info->have_repository)
-               return find_unique_abbrev(oid, abbrev);
+               return repo_find_unique_abbrev(the_repository, oid, abbrev);
        else {
                char *hex = oid_to_hex(oid);
                if (abbrev < 0)
@@ -4674,10 +4710,9 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
                options->flags.ignore_untracked_in_submodules = 1;
 
        if (diff_no_prefix) {
-               options->a_prefix = options->b_prefix = "";
+               diff_set_noprefix(options);
        } else if (!diff_mnemonic_prefix) {
-               options->a_prefix = "a/";
-               options->b_prefix = "b/";
+               diff_set_default_prefix(options);
        }
 
        options->color_moved = diff_color_moved_default;
@@ -4721,6 +4756,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 |
@@ -4775,6 +4835,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 |
@@ -4828,8 +4892,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;
@@ -4906,6 +4970,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;
@@ -4925,6 +4990,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;
 }
@@ -4988,7 +5054,7 @@ static int diff_opt_find_object(const struct option *option,
        struct object_id oid;
 
        BUG_ON_OPT_NEG(unset);
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                return error(_("unable to resolve '%s'"), arg);
 
        if (!opt->objfind)
@@ -5124,6 +5190,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;
@@ -5261,8 +5328,18 @@ static int diff_opt_no_prefix(const struct option *opt,
 
        BUG_ON_OPT_NEG(unset);
        BUG_ON_OPT_ARG(optarg);
-       options->a_prefix = "";
-       options->b_prefix = "";
+       diff_set_noprefix(options);
+       return 0;
+}
+
+static int diff_opt_default_prefix(const struct option *opt,
+                                  const char *optarg, int unset)
+{
+       struct diff_options *options = opt->value;
+
+       BUG_ON_OPT_NEG(unset);
+       BUG_ON_OPT_ARG(optarg);
+       diff_set_default_prefix(options);
        return 0;
 }
 
@@ -5451,6 +5528,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)
 {
@@ -5459,9 +5540,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),
@@ -5470,9 +5550,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,
@@ -5481,12 +5561,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,
@@ -5502,9 +5582,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),
@@ -5555,6 +5635,9 @@ struct option *add_diff_options(const struct option *opts,
                OPT_CALLBACK_F(0, "no-prefix", options, NULL,
                               N_("do not show any source or destination prefix"),
                               PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_no_prefix),
+               OPT_CALLBACK_F(0, "default-prefix", options, NULL,
+                              N_("use default prefixes a/ and b/"),
+                              PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_default_prefix),
                OPT_INTEGER_F(0, "inter-hunk-context", &options->interhunkcontext,
                              N_("show context between diff hunks up to the specified number of lines"),
                              PARSE_OPT_NONEG),
@@ -6130,6 +6213,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)
@@ -6608,6 +6693,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) {
@@ -6629,21 +6729,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);
@@ -6860,7 +6945,7 @@ void diffcore_std(struct diff_options *options)
         * If no prefetching occurs, diffcore_rename() will prefetch if it
         * decides that it needs inexact rename detection.
         */
-       if (options->repo == the_repository && has_promisor_remote() &&
+       if (options->repo == the_repository && repo_has_promisor_remote(the_repository) &&
            (options->output_format & output_formats_to_prefetch ||
             options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK))
                diff_queued_diff_prefetch(options->repo);
@@ -6897,16 +6982,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;
@@ -6953,6 +7036,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 8d770b1d579c8ec61ce52c4ac4c9df799c509901..caf1528bf077cda0be89882b5ef856fe34dd3999 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -4,10 +4,11 @@
 #ifndef DIFF_H
 #define DIFF_H
 
-#include "tree-walk.h"
+#include "hash-ll.h"
 #include "pathspec.h"
-#include "object.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,
@@ -71,7 +72,6 @@ struct oid_array;
 struct option;
 struct repository;
 struct rev_info;
-struct strbuf;
 struct userdiff_driver;
 
 typedef int (*pathchange_fn_t)(struct diff_options *options,
@@ -497,6 +497,8 @@ void diff_tree_combined(const struct object_id *oid, const struct oid_array *par
 void diff_tree_combined_merge(const struct commit *commit, struct rev_info *rev);
 
 void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b);
+void diff_set_noprefix(struct diff_options *options);
+void diff_set_default_prefix(struct diff_options *options);
 
 int diff_can_quit_early(struct diff_options *);
 
@@ -531,17 +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);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts)
-#endif
+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
@@ -617,7 +626,7 @@ void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);
 #define DIFF_STATUS_FILTER_BROKEN      'B'
 
 /*
- * This is different from find_unique_abbrev() in that
+ * This is different from repo_find_unique_abbrev() in that
  * it stuffs the result with dots for alignment.
  */
 const char *diff_aligned_abbrev(const struct object_id *sha1, int);
@@ -628,17 +637,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 **);
@@ -697,4 +706,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 0d4a14964d00b3a77016fb0ed677b1847d1ab72c..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,
@@ -65,7 +67,7 @@ static int should_break(struct repository *r,
            oideq(&src->oid, &dst->oid))
                return 0; /* they are the same */
 
-       if (r == the_repository && has_promisor_remote()) {
+       if (r == the_repository && repo_has_promisor_remote(the_repository)) {
                options.missing_object_cb = diff_queued_diff_prefetch;
                options.missing_object_data = r;
        }
index 18d8f766d70108e868a5bb21ad6c45550bb8c34d..c30b56e983bda39e18eda24bb81608ae7a33942c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
 
index 19e73311f9cd830da70428439b7b6a14d5345eec..e7d20ebd2d1b45b073ac2825b9371986d305ee29 100644 (file)
@@ -1,9 +1,11 @@
 /*
  * Copyright (C) 2005 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "wildmatch.h"
 
 static char **order;
 static int order_cnt;
index 03fcbcb40ba6ab42037d1c429658ed48ee40982f..b195fa4eb3c045c030a47c84edcaa702e447c8f8 100644 (file)
@@ -2,12 +2,13 @@
  * Copyright (C) 2005 Junio C Hamano
  * Copyright (C) 2010 Google Inc.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "xdiff-interface.h"
 #include "kwset.h"
-#include "commit.h"
+#include "oidset.h"
+#include "pretty.h"
 #include "quote.h"
 
 typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,
index c0422d9e709a65d5a77d1444fcff0a4d313299bd..5a6e2bcac7147e487624c1bf53e1572a54b0d93d 100644 (file)
@@ -2,14 +2,18 @@
  *
  * Copyright (C) 2005 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.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"
 #include "progress.h"
 #include "promisor-remote.h"
+#include "string-list.h"
 #include "strmap.h"
+#include "trace2.h"
 
 /* Table of rename/copy destinations */
 
@@ -981,7 +985,7 @@ static int find_basename_matches(struct diff_options *options,
                        strintmap_set(&dests, base, i);
        }
 
-       if (options->repo == the_repository && has_promisor_remote()) {
+       if (options->repo == the_repository && repo_has_promisor_remote(the_repository)) {
                dpf_options.missing_object_cb = basename_prefetch;
                dpf_options.missing_object_data = &prefetch_options;
        }
@@ -1567,7 +1571,7 @@ void diffcore_rename_extended(struct diff_options *options,
 
        /* Finish setting up dpf_options */
        prefetch_options.skip_unmodified = skip_unmodified;
-       if (options->repo == the_repository && has_promisor_remote()) {
+       if (options->repo == the_repository && repo_has_promisor_remote(the_repository)) {
                dpf_options.missing_object_cb = inexact_prefetch;
                dpf_options.missing_object_data = &prefetch_options;
        }
index 445f060ab0010ede4009b92c3d4acb0b34f644b9..533986cf632d4231fd067b244e2776a256af8e3e 100644 (file)
@@ -2,7 +2,8 @@
  * Copyright (C) 2021, Google LLC.
  * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
 #include "diff.h"
 #include "diffcore.h"
 
index 9b588a1ee15a3bc93eaf4464f7d1e74265b2f3a2..5ffe4ec788f84044df42b13eb847dec1f4e1fd36 100644 (file)
@@ -4,9 +4,11 @@
 #ifndef DIFFCORE_H
 #define DIFFCORE_H
 
-#include "cache.h"
+#include "hash-ll.h"
 
 struct diff_options;
+struct mem_pool;
+struct oid_array;
 struct repository;
 struct strintmap;
 struct strmap;
index cedd30475992d41fd8371d51572117c71e9e9b6c..278b04243a3f40e63df433eea9549f90aed1c34d 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "dir.h"
 #include "iterator.h"
 #include "dir-iterator.h"
diff --git a/dir.c b/dir.c
index 4e99f0c868f3d7955c4a6f84bf22bbce0d917ae3..8486e4d56ff50cafd14aa3ef00ee89c069d87269 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -5,10 +5,17 @@
  * Copyright (C) Linus Torvalds, 2005-2006
  *              Junio Hamano, 2005-2006
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
+#include "convert.h"
 #include "dir.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object-file.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"
 
 /*
  * Tells read_directory_recursive how a file or directory should be treated.
@@ -267,7 +280,7 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,
        *size_out = 0;
        *data_out = NULL;
 
-       data = read_object_file(oid, &type, &sz);
+       data = repo_read_object_file(the_repository, oid, &type, &sz);
        if (!data || type != OBJ_BLOB) {
                free(data);
                return -1;
@@ -363,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 */
@@ -1190,7 +1203,7 @@ struct pattern_list *add_pattern_list(struct dir_struct *dir,
        struct pattern_list *pl;
        struct exclude_list_group *group;
 
-       group = &dir->exclude_list_group[group_type];
+       group = &dir->internal.exclude_list_group[group_type];
        ALLOC_GROW(group->pl, group->nr + 1, group->alloc);
        pl = &group->pl[group->nr++];
        memset(pl, 0, sizeof(*pl));
@@ -1211,7 +1224,7 @@ static void add_patterns_from_file_1(struct dir_struct *dir, const char *fname,
         * differently when dir->untracked is non-NULL.
         */
        if (!dir->untracked)
-               dir->unmanaged_exclude_files++;
+               dir->internal.unmanaged_exclude_files++;
        pl = add_pattern_list(dir, EXC_FILE, fname);
        if (add_patterns(fname, "", 0, pl, NULL, 0, oid_stat) < 0)
                die(_("cannot use %s as an exclude file"), fname);
@@ -1219,7 +1232,7 @@ static void add_patterns_from_file_1(struct dir_struct *dir, const char *fname,
 
 void add_patterns_from_file(struct dir_struct *dir, const char *fname)
 {
-       dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */
+       dir->internal.unmanaged_exclude_files++; /* see validate_untracked_cache() */
        add_patterns_from_file_1(dir, fname, NULL);
 }
 
@@ -1519,7 +1532,7 @@ static struct path_pattern *last_matching_pattern_from_lists(
        struct exclude_list_group *group;
        struct path_pattern *pattern;
        for (i = EXC_CMDL; i <= EXC_FILE; i++) {
-               group = &dir->exclude_list_group[i];
+               group = &dir->internal.exclude_list_group[i];
                for (j = group->nr - 1; j >= 0; j--) {
                        pattern = last_matching_pattern_from_list(
                                pathname, pathlen, basename, dtype_p,
@@ -1545,20 +1558,20 @@ static void prep_exclude(struct dir_struct *dir,
        struct untracked_cache_dir *untracked;
        int current;
 
-       group = &dir->exclude_list_group[EXC_DIRS];
+       group = &dir->internal.exclude_list_group[EXC_DIRS];
 
        /*
         * Pop the exclude lists from the EXCL_DIRS exclude_list_group
         * which originate from directories not in the prefix of the
         * path being checked.
         */
-       while ((stk = dir->exclude_stack) != NULL) {
+       while ((stk = dir->internal.exclude_stack) != NULL) {
                if (stk->baselen <= baselen &&
-                   !strncmp(dir->basebuf.buf, base, stk->baselen))
+                   !strncmp(dir->internal.basebuf.buf, base, stk->baselen))
                        break;
-               pl = &group->pl[dir->exclude_stack->exclude_ix];
-               dir->exclude_stack = stk->prev;
-               dir->pattern = NULL;
+               pl = &group->pl[dir->internal.exclude_stack->exclude_ix];
+               dir->internal.exclude_stack = stk->prev;
+               dir->internal.pattern = NULL;
                free((char *)pl->src); /* see strbuf_detach() below */
                clear_pattern_list(pl);
                free(stk);
@@ -1566,7 +1579,7 @@ static void prep_exclude(struct dir_struct *dir,
        }
 
        /* Skip traversing into sub directories if the parent is excluded */
-       if (dir->pattern)
+       if (dir->internal.pattern)
                return;
 
        /*
@@ -1574,12 +1587,12 @@ static void prep_exclude(struct dir_struct *dir,
         * memset(dir, 0, sizeof(*dir)) before use. Changing all of
         * them seems lots of work for little benefit.
         */
-       if (!dir->basebuf.buf)
-               strbuf_init(&dir->basebuf, PATH_MAX);
+       if (!dir->internal.basebuf.buf)
+               strbuf_init(&dir->internal.basebuf, PATH_MAX);
 
        /* Read from the parent directories and push them down. */
        current = stk ? stk->baselen : -1;
-       strbuf_setlen(&dir->basebuf, current < 0 ? 0 : current);
+       strbuf_setlen(&dir->internal.basebuf, current < 0 ? 0 : current);
        if (dir->untracked)
                untracked = stk ? stk->ucd : dir->untracked->root;
        else
@@ -1599,32 +1612,33 @@ static void prep_exclude(struct dir_struct *dir,
                                die("oops in prep_exclude");
                        cp++;
                        untracked =
-                               lookup_untracked(dir->untracked, untracked,
+                               lookup_untracked(dir->untracked,
+                                                untracked,
                                                 base + current,
                                                 cp - base - current);
                }
-               stk->prev = dir->exclude_stack;
+               stk->prev = dir->internal.exclude_stack;
                stk->baselen = cp - base;
                stk->exclude_ix = group->nr;
                stk->ucd = untracked;
                pl = add_pattern_list(dir, EXC_DIRS, NULL);
-               strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
-               assert(stk->baselen == dir->basebuf.len);
+               strbuf_add(&dir->internal.basebuf, base + current, stk->baselen - current);
+               assert(stk->baselen == dir->internal.basebuf.len);
 
                /* Abort if the directory is excluded */
                if (stk->baselen) {
                        int dt = DT_DIR;
-                       dir->basebuf.buf[stk->baselen - 1] = 0;
-                       dir->pattern = last_matching_pattern_from_lists(dir,
+                       dir->internal.basebuf.buf[stk->baselen - 1] = 0;
+                       dir->internal.pattern = last_matching_pattern_from_lists(dir,
                                                                        istate,
-                               dir->basebuf.buf, stk->baselen - 1,
-                               dir->basebuf.buf + current, &dt);
-                       dir->basebuf.buf[stk->baselen - 1] = '/';
-                       if (dir->pattern &&
-                           dir->pattern->flags & PATTERN_FLAG_NEGATIVE)
-                               dir->pattern = NULL;
-                       if (dir->pattern) {
-                               dir->exclude_stack = stk;
+                               dir->internal.basebuf.buf, stk->baselen - 1,
+                               dir->internal.basebuf.buf + current, &dt);
+                       dir->internal.basebuf.buf[stk->baselen - 1] = '/';
+                       if (dir->internal.pattern &&
+                           dir->internal.pattern->flags & PATTERN_FLAG_NEGATIVE)
+                               dir->internal.pattern = NULL;
+                       if (dir->internal.pattern) {
+                               dir->internal.exclude_stack = stk;
                                return;
                        }
                }
@@ -1647,15 +1661,15 @@ static void prep_exclude(struct dir_struct *dir,
                      */
                     !is_null_oid(&untracked->exclude_oid))) {
                        /*
-                        * dir->basebuf gets reused by the traversal, but we
-                        * need fname to remain unchanged to ensure the src
-                        * member of each struct path_pattern correctly
+                        * dir->internal.basebuf gets reused by the traversal,
+                        * but we need fname to remain unchanged to ensure the
+                        * src member of each struct path_pattern correctly
                         * back-references its source file.  Other invocations
                         * of add_pattern_list provide stable strings, so we
                         * strbuf_detach() and free() here in the caller.
                         */
                        struct strbuf sb = STRBUF_INIT;
-                       strbuf_addbuf(&sb, &dir->basebuf);
+                       strbuf_addbuf(&sb, &dir->internal.basebuf);
                        strbuf_addstr(&sb, dir->exclude_per_dir);
                        pl->src = strbuf_detach(&sb, NULL);
                        add_patterns(pl->src, pl->src, stk->baselen, pl, istate,
@@ -1681,10 +1695,10 @@ static void prep_exclude(struct dir_struct *dir,
                        invalidate_gitignore(dir->untracked, untracked);
                        oidcpy(&untracked->exclude_oid, &oid_stat.oid);
                }
-               dir->exclude_stack = stk;
+               dir->internal.exclude_stack = stk;
                current = stk->baselen;
        }
-       strbuf_setlen(&dir->basebuf, baselen);
+       strbuf_setlen(&dir->internal.basebuf, baselen);
 }
 
 /*
@@ -1704,8 +1718,8 @@ struct path_pattern *last_matching_pattern(struct dir_struct *dir,
 
        prep_exclude(dir, istate, pathname, basename-pathname);
 
-       if (dir->pattern)
-               return dir->pattern;
+       if (dir->internal.pattern)
+               return dir->internal.pattern;
 
        return last_matching_pattern_from_lists(dir, istate, pathname, pathlen,
                        basename, dtype_p);
@@ -1742,7 +1756,7 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir,
        if (index_file_exists(istate, pathname, len, ignore_case))
                return NULL;
 
-       ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
+       ALLOC_GROW(dir->entries, dir->nr+1, dir->internal.alloc);
        return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
 }
 
@@ -1753,7 +1767,7 @@ struct dir_entry *dir_add_ignored(struct dir_struct *dir,
        if (!index_name_is_other(istate, pathname, len))
                return NULL;
 
-       ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
+       ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->internal.ignored_alloc);
        return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
 }
 
@@ -2569,7 +2583,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 
        if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only))
                goto out;
-       dir->visited_directories++;
+       dir->internal.visited_directories++;
 
        if (untracked)
                untracked->check_only = !!check_only;
@@ -2578,7 +2592,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
                /* check how the file or directory should be treated */
                state = treat_path(dir, untracked, &cdir, istate, &path,
                                   baselen, pathspec);
-               dir->visited_paths++;
+               dir->internal.visited_paths++;
 
                if (state > dir_state)
                        dir_state = state;
@@ -2586,7 +2600,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
                /* recurse into subdir if instructed by treat_path */
                if (state == path_recurse) {
                        struct untracked_cache_dir *ud;
-                       ud = lookup_untracked(dir->untracked, untracked,
+                       ud = lookup_untracked(dir->untracked,
+                                             untracked,
                                              path.buf + baselen,
                                              path.len - baselen);
                        subdir_state =
@@ -2846,7 +2861,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
         * condition also catches running setup_standard_excludes()
         * before setting dir->untracked!
         */
-       if (dir->unmanaged_exclude_files)
+       if (dir->internal.unmanaged_exclude_files)
                return NULL;
 
        /*
@@ -2875,7 +2890,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
         * EXC_CMDL is not considered in the cache. If people set it,
         * skip the cache.
         */
-       if (dir->exclude_list_group[EXC_CMDL].nr)
+       if (dir->internal.exclude_list_group[EXC_CMDL].nr)
                return NULL;
 
        if (!ident_in_untracked(dir->untracked)) {
@@ -2935,15 +2950,15 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
 
        /* Validate $GIT_DIR/info/exclude and core.excludesfile */
        root = dir->untracked->root;
-       if (!oideq(&dir->ss_info_exclude.oid,
+       if (!oideq(&dir->internal.ss_info_exclude.oid,
                   &dir->untracked->ss_info_exclude.oid)) {
                invalidate_gitignore(dir->untracked, root);
-               dir->untracked->ss_info_exclude = dir->ss_info_exclude;
+               dir->untracked->ss_info_exclude = dir->internal.ss_info_exclude;
        }
-       if (!oideq(&dir->ss_excludes_file.oid,
+       if (!oideq(&dir->internal.ss_excludes_file.oid,
                   &dir->untracked->ss_excludes_file.oid)) {
                invalidate_gitignore(dir->untracked, root);
-               dir->untracked->ss_excludes_file = dir->ss_excludes_file;
+               dir->untracked->ss_excludes_file = dir->internal.ss_excludes_file;
        }
 
        /* Make sure this directory is not dropped out at saving phase */
@@ -2969,9 +2984,9 @@ static void emit_traversal_statistics(struct dir_struct *dir,
        }
 
        trace2_data_intmax("read_directory", repo,
-                          "directories-visited", dir->visited_directories);
+                          "directories-visited", dir->internal.visited_directories);
        trace2_data_intmax("read_directory", repo,
-                          "paths-visited", dir->visited_paths);
+                          "paths-visited", dir->internal.visited_paths);
 
        if (!dir->untracked)
                return;
@@ -2993,8 +3008,8 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
        struct untracked_cache_dir *untracked;
 
        trace2_region_enter("dir", "read_directory", istate->repo);
-       dir->visited_paths = 0;
-       dir->visited_directories = 0;
+       dir->internal.visited_paths = 0;
+       dir->internal.visited_directories = 0;
 
        if (has_symlink_leading_path(path, len)) {
                trace2_region_leave("dir", "read_directory", istate->repo);
@@ -3342,14 +3357,14 @@ void setup_standard_excludes(struct dir_struct *dir)
                excludes_file = xdg_config_home("ignore");
        if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
                add_patterns_from_file_1(dir, excludes_file,
-                                        dir->untracked ? &dir->ss_excludes_file : NULL);
+                                        dir->untracked ? &dir->internal.ss_excludes_file : NULL);
 
        /* per repository user preference */
        if (startup_info->have_repository) {
                const char *path = git_path_info_exclude();
                if (!access_or_warn(path, R_OK, 0))
                        add_patterns_from_file_1(dir, path,
-                                                dir->untracked ? &dir->ss_info_exclude : NULL);
+                                                dir->untracked ? &dir->internal.ss_info_exclude : NULL);
        }
 }
 
@@ -3405,7 +3420,7 @@ void dir_clear(struct dir_struct *dir)
        struct dir_struct new = DIR_INIT;
 
        for (i = EXC_CMDL; i <= EXC_FILE; i++) {
-               group = &dir->exclude_list_group[i];
+               group = &dir->internal.exclude_list_group[i];
                for (j = 0; j < group->nr; j++) {
                        pl = &group->pl[j];
                        if (i == EXC_DIRS)
@@ -3422,13 +3437,13 @@ void dir_clear(struct dir_struct *dir)
        free(dir->ignored);
        free(dir->entries);
 
-       stk = dir->exclude_stack;
+       stk = dir->internal.exclude_stack;
        while (stk) {
                struct exclude_stack *prev = stk->prev;
                free(stk);
                stk = prev;
        }
-       strbuf_release(&dir->basebuf);
+       strbuf_release(&dir->internal.basebuf);
 
        memcpy(dir, &new, sizeof(*dir));
 }
diff --git a/dir.h b/dir.h
index 8acfc044181ca2f47aa39bef25713b1a811e987c..ad06682fd54b3e7ae47d6f8a8d80048da0324f01 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -1,10 +1,14 @@
 #ifndef DIR_H
 #define DIR_H
 
-#include "cache.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
@@ -39,6 +43,8 @@
  *
  */
 
+struct repository;
+
 struct dir_entry {
        unsigned int len;
        char name[FLEX_ARRAY]; /* more */
@@ -212,17 +218,6 @@ struct untracked_cache {
  */
 struct dir_struct {
 
-       /* The number of members in `entries[]` array. */
-       int nr;
-
-       /* Internal use; keeps track of allocation of `entries[]` array.*/
-       int alloc;
-
-       /* The number of members in `ignored[]` array. */
-       int ignored_nr;
-
-       int ignored_alloc;
-
        /* bit-field of options */
        enum {
 
@@ -287,60 +282,81 @@ struct dir_struct {
                DIR_SKIP_NESTED_GIT = 1<<9
        } flags;
 
+       /* The number of members in `entries[]` array. */
+       int nr; /* output only */
+
+       /* The number of members in `ignored[]` array. */
+       int ignored_nr; /* output only */
+
        /* An array of `struct dir_entry`, each element of which describes a path. */
-       struct dir_entry **entries;
+       struct dir_entry **entries; /* output only */
 
        /**
         * used for ignored paths with the `DIR_SHOW_IGNORED_TOO` and
         * `DIR_COLLECT_IGNORED` flags.
         */
-       struct dir_entry **ignored;
+       struct dir_entry **ignored; /* output only */
+
+       /* Enable/update untracked file cache if set */
+       struct untracked_cache *untracked;
 
        /**
-        * The name of the file to be read in each directory for excluded files
-        * (typically `.gitignore`).
+        * Deprecated: ls-files is the only allowed caller; all other callers
+        * should leave this as NULL; it pre-dated the
+        * setup_standard_excludes() mechanism that replaces this.
+        *
+        * This field tracks the name of the file to be read in each directory
+        * for excluded files (typically `.gitignore`).
         */
        const char *exclude_per_dir;
 
-       /*
-        * We maintain three groups of exclude pattern lists:
-        *
-        * EXC_CMDL lists patterns explicitly given on the command line.
-        * EXC_DIRS lists patterns obtained from per-directory ignore files.
-        * EXC_FILE lists patterns from fallback ignore files, e.g.
-        *   - .git/info/exclude
-        *   - core.excludesfile
-        *
-        * Each group contains multiple exclude lists, a single list
-        * per source.
-        */
+       struct dir_struct_internal {
+               /* Keeps track of allocation of `entries[]` array.*/
+               int alloc;
+
+               /* Keeps track of allocation of `ignored[]` array. */
+               int ignored_alloc;
+
+               /*
+                * We maintain three groups of exclude pattern lists:
+                *
+                * EXC_CMDL lists patterns explicitly given on the command line.
+                * EXC_DIRS lists patterns obtained from per-directory ignore
+                *          files.
+                * EXC_FILE lists patterns from fallback ignore files, e.g.
+                *   - .git/info/exclude
+                *   - core.excludesfile
+                *
+                * Each group contains multiple exclude lists, a single list
+                * per source.
+                */
 #define EXC_CMDL 0
 #define EXC_DIRS 1
 #define EXC_FILE 2
-       struct exclude_list_group exclude_list_group[3];
-
-       /*
-        * Temporary variables which are used during loading of the
-        * per-directory exclude lists.
-        *
-        * exclude_stack points to the top of the exclude_stack, and
-        * basebuf contains the full path to the current
-        * (sub)directory in the traversal. Exclude points to the
-        * matching exclude struct if the directory is excluded.
-        */
-       struct exclude_stack *exclude_stack;
-       struct path_pattern *pattern;
-       struct strbuf basebuf;
+               struct exclude_list_group exclude_list_group[3];
 
-       /* Enable untracked file cache if set */
-       struct untracked_cache *untracked;
-       struct oid_stat ss_info_exclude;
-       struct oid_stat ss_excludes_file;
-       unsigned unmanaged_exclude_files;
-
-       /* Stats about the traversal */
-       unsigned visited_paths;
-       unsigned visited_directories;
+               /*
+                * Temporary variables which are used during loading of the
+                * per-directory exclude lists.
+                *
+                * exclude_stack points to the top of the exclude_stack, and
+                * basebuf contains the full path to the current
+                * (sub)directory in the traversal. Exclude points to the
+                * matching exclude struct if the directory is excluded.
+                */
+               struct exclude_stack *exclude_stack;
+               struct path_pattern *pattern;
+               struct strbuf basebuf;
+
+               /* Additional metadata related to 'untracked' */
+               struct oid_stat ss_info_exclude;
+               struct oid_stat ss_excludes_file;
+               unsigned unmanaged_exclude_files;
+
+               /* Stats about the traversal */
+               unsigned visited_paths;
+               unsigned visited_directories;
+       } internal;
 };
 
 #define DIR_INIT { 0 }
@@ -363,10 +379,6 @@ int count_slashes(const char *s);
 int simple_length(const char *match);
 int no_wildcard(const char *string);
 char *common_prefix(const struct pathspec *pathspec);
-int match_pathspec(struct index_state *istate,
-                  const struct pathspec *pathspec,
-                  const char *name, int namelen,
-                  int prefix, char *seen, int is_dir);
 int report_path_error(const char *ps_matched, const struct pathspec *pathspec);
 int within_depth(const char *name, int namelen, int depth, int max_depth);
 
@@ -533,15 +545,6 @@ int submodule_path_match(struct index_state *istate,
                         const char *submodule_name,
                         char *seen);
 
-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));
-}
-
 static inline int dir_path_match(struct index_state *istate,
                                 const struct dir_entry *ent,
                                 const struct pathspec *pathspec,
@@ -642,4 +645,5 @@ static inline int starts_with_dot_dot_slash_native(const char *const path)
 
        return path_match_flags(path, what | PATH_MATCH_NATIVE);
 }
+
 #endif
index 008c04fe2f6e0a8b39bc02005f0a576d92784bae..b67b802ddf8493ea25ccbb1fc5c046240bfe917d 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -1,5 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
 #include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "pager.h"
+#include "path.h"
 #include "strbuf.h"
 #include "strvec.h"
 #include "run-command.h"
@@ -126,3 +133,31 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
 {
        return launch_specified_editor(git_sequence_editor(), path, buffer, env);
 }
+
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+                             const char *const *env)
+{
+       char *path2 = NULL;
+       int fd, res = 0;
+
+       if (!is_absolute_path(path))
+               path = path2 = xstrdup(git_path("%s", path));
+
+       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+       if (fd < 0)
+               res = error_errno(_("could not open '%s' for writing"), path);
+       else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
+               res = error_errno(_("could not write to '%s'"), path);
+               close(fd);
+       } else if (close(fd) < 0)
+               res = error_errno(_("could not close '%s'"), path);
+       else {
+               strbuf_reset(buffer);
+               if (launch_editor(path, buffer, env) < 0)
+                       res = error_errno(_("could not edit '%s'"), path);
+               unlink(path);
+       }
+
+       free(path2);
+       return res;
+}
diff --git a/editor.h b/editor.h
new file mode 100644 (file)
index 0000000..8016bb5
--- /dev/null
+++ b/editor.h
@@ -0,0 +1,34 @@
+#ifndef EDITOR_H
+#define EDITOR_H
+
+struct strbuf;
+
+const char *git_editor(void);
+const char *git_sequence_editor(void);
+int is_terminal_dumb(void);
+
+/**
+ * Launch the user preferred editor to edit a file and fill the buffer
+ * with the file's contents upon the user completing their editing. The
+ * third argument can be used to set the environment which the editor is
+ * run in. If the buffer is NULL the editor is launched as usual but the
+ * file's contents are not read into the buffer upon completion.
+ */
+int launch_editor(const char *path, struct strbuf *buffer,
+                 const char *const *env);
+
+int launch_sequence_editor(const char *path, struct strbuf *buffer,
+                          const char *const *env);
+
+/*
+ * In contrast to `launch_editor()`, this function writes out the contents
+ * of the specified file first, then clears the `buffer`, then launches
+ * the editor and reads back in the file contents into the `buffer`.
+ * Finally, it deletes the temporary file.
+ *
+ * If `path` is relative, it refers to a file in the `.git` directory.
+ */
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+                             const char *const *env);
+
+#endif
diff --git a/entry.c b/entry.c
index 971ab268714b96cdaa179ae7589c8377ff728e74..43767f9043c0cbb97ec3257fd78b0a985e5a8f77 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,9 +1,15 @@
-#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"
 #include "progress.h"
 #include "fsmonitor.h"
 #include "entry.h"
@@ -86,7 +92,8 @@ void *read_blob_entry(const struct cache_entry *ce, size_t *size)
 {
        enum object_type type;
        unsigned long ul;
-       void *blob_data = read_object_file(&ce->oid, &type, &ul);
+       void *blob_data = repo_read_object_file(the_repository, &ce->oid,
+                                               &type, &ul);
 
        *size = ul;
        if (blob_data) {
diff --git a/entry.h b/entry.h
index 2d4fbb88c8ffabbd36faec0247d5a39a30f99c4f..7329f918a97ee3f80aeeaff07e4236143fcf3cbf 100644 (file)
--- a/entry.h
+++ b/entry.h
@@ -1,9 +1,11 @@
 #ifndef ENTRY_H
 #define ENTRY_H
 
-#include "cache.h"
 #include "convert.h"
 
+struct cache_entry;
+struct index_state;
+
 struct checkout {
        struct index_state *istate;
        const char *base_dir;
index 1ee3686fd8a34270db8d47738f2ea12fcdbc1976..f98d76f08047f14f49e9d3c3d1a4232c500efbf1 100644 (file)
@@ -7,19 +7,28 @@
  * even if you might want to know where the git directory etc
  * are.
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "branch.h"
+#include "convert.h"
 #include "environment.h"
+#include "gettext.h"
 #include "repository.h"
 #include "config.h"
 #include "refs.h"
 #include "fmt-merge-msg.h"
 #include "commit.h"
 #include "strvec.h"
-#include "object-store.h"
+#include "object-file.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 "write-or-die.h"
 
 int trust_executable_bit = 1;
 int trust_ctime = 1;
@@ -33,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;
@@ -50,16 +58,13 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 96 * 1024 * 1024;
 unsigned long big_file_threshold = 512 * 1024 * 1024;
-int pager_use_color = 1;
 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";
-unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
 enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
 enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
 enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
@@ -68,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;
@@ -103,7 +108,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,
@@ -177,7 +182,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 d438b5c8f3a62226a3a1cc32bb9ab9d9def25a4e..c5377473c683390992315f69a63c557b25c655bb 100644 (file)
@@ -1,7 +1,15 @@
 #ifndef ENVIRONMENT_H
 #define ENVIRONMENT_H
 
-#include "strvec.h"
+struct repository;
+struct strvec;
+
+/*
+ * The character that begins a commented line in user-editable file
+ * that is subject to stripspace.
+ */
+extern char comment_line_char;
+extern int auto_comment_line_char;
 
 /*
  * Wrapper of getenv() that returns a strdup value. This value is kept
  */
 const char *getenv_safe(struct strvec *argv, const char *name);
 
+/* Double-check local_repo_env below if you add to this list. */
+#define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
+#define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
+#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
+#define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
+#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
+#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
+#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
+#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
+#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
+#define CONFIG_ENVIRONMENT "GIT_CONFIG"
+#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
+#define CONFIG_COUNT_ENVIRONMENT "GIT_CONFIG_COUNT"
+#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
+#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
+#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
+#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
+#define GITATTRIBUTES_FILE ".gitattributes"
+#define INFOATTRIBUTES_FILE "info/attributes"
+#define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define GITMODULES_FILE ".gitmodules"
+#define GITMODULES_INDEX ":.gitmodules"
+#define GITMODULES_HEAD "HEAD:.gitmodules"
+#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
+#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
+#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
+#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
+#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
+#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
+#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
+#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
+#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
+#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
+#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
+#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
+#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
+
+/*
+ * Environment variable used in handshaking the wire protocol.
+ * Contains a colon ':' separated list of keys with optional values
+ * 'key[=value]'.  Presence of unknown keys and values must be
+ * ignored.
+ */
+#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
+/* HTTP header used to handshake the wire protocol */
+#define GIT_PROTOCOL_HEADER "Git-Protocol"
+
+/*
+ * This environment variable is expected to contain a boolean indicating
+ * whether we should or should not treat:
+ *
+ *   GIT_DIR=foo.git git ...
+ *
+ * as if GIT_WORK_TREE=. was given. It's not expected that users will make use
+ * of this, but we use it internally to communicate to sub-processes that we
+ * are in a bare repo. If not set, defaults to true.
+ */
+#define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
+
+/*
+ * Repository-local GIT_* environment variables; these will be cleared
+ * when git spawns a sub-process that runs inside another repository.
+ * The array is NULL-terminated, which makes it easy to pass in the "env"
+ * parameter of a run-command invocation, or to do a simple walk.
+ */
+extern const char * const local_repo_env[];
+
+void setup_git_env(const char *git_dir);
+
+/*
+ * Returns true iff we have a configured git repository (either via
+ * setup_git_directory, or in the environment via $GIT_DIR).
+ */
+int have_git_dir(void);
+
+extern int is_bare_repository_cfg;
+int is_bare_repository(void);
+extern char *git_work_tree_cfg;
+const char *get_git_dir(void);
+const char *get_git_common_dir(void);
+const char *get_object_directory(void);
+char *get_index_file(void);
+char *get_graft_file(struct repository *r);
+void set_git_dir(const char *path, int make_realpath);
+const char *get_git_namespace(void);
+const char *strip_namespace(const char *namespaced_ref);
+const char *get_git_work_tree(void);
+void set_git_work_tree(const char *tree);
+
+#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+
+/* Environment bits from configuration mechanism */
+extern int trust_executable_bit;
+extern int trust_ctime;
+extern int check_stat;
+extern int has_symlinks;
+extern int minimum_abbrev, default_abbrev;
+extern int ignore_case;
+extern int assume_unchanged;
+extern int prefer_symlink_refs;
+extern int warn_ambiguous_refs;
+extern int warn_on_object_refname_ambiguity;
+extern char *apply_default_whitespace;
+extern char *apply_default_ignorewhitespace;
+extern const char *git_attributes_file;
+extern const char *git_hooks_path;
+extern int zlib_compression_level;
+extern int pack_compression_level;
+extern size_t packed_git_window_size;
+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;
+
+/*
+ * Accessors for the core.sharedrepository config which lazy-load the value
+ * from the config (if not already set). The "reset" function can be
+ * used to unset "set" or cached value, meaning that the value will be loaded
+ * fresh from the config file on the next call to get_shared_repository().
+ */
+void set_shared_repository(int value);
+int get_shared_repository(void);
+void reset_shared_repository(void);
+
+extern int core_preload_index;
+extern int precomposed_unicode;
+extern int protect_hfs;
+extern int protect_ntfs;
+
+extern int core_apply_sparse_checkout;
+extern int core_sparse_checkout_cone;
+extern int sparse_expect_files_outside_of_patterns;
+
+/*
+ * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
+ */
+int use_optional_locks(void);
+
+enum log_refs_config {
+       LOG_REFS_UNSET = -1,
+       LOG_REFS_NONE = 0,
+       LOG_REFS_NORMAL,
+       LOG_REFS_ALWAYS
+};
+extern enum log_refs_config log_all_ref_updates;
+
+enum rebase_setup_type {
+       AUTOREBASE_NEVER = 0,
+       AUTOREBASE_LOCAL,
+       AUTOREBASE_REMOTE,
+       AUTOREBASE_ALWAYS
+};
+
+enum push_default_type {
+       PUSH_DEFAULT_NOTHING = 0,
+       PUSH_DEFAULT_MATCHING,
+       PUSH_DEFAULT_SIMPLE,
+       PUSH_DEFAULT_UPSTREAM,
+       PUSH_DEFAULT_CURRENT,
+       PUSH_DEFAULT_UNSPECIFIED
+};
+
+extern enum rebase_setup_type autorebase;
+extern enum push_default_type push_default;
+
+enum object_creation_mode {
+       OBJECT_CREATION_USES_HARDLINKS = 0,
+       OBJECT_CREATION_USES_RENAMES = 1
+};
+
+extern enum object_creation_mode object_creation_mode;
+
+extern char *notes_ref_name;
+
+extern int grafts_keep_true_parents;
+
+extern int repository_format_precious_objects;
+
+/*
+ * Create a temporary file rooted in the object database directory, or
+ * die on failure. The filename is taken from "pattern", which should have the
+ * usual "XXXXXX" trailer, and the resulting filename is written into the
+ * "template" buffer. Returns the open descriptor.
+ */
+int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
+
+/*
+ * Create a pack .keep file named "name" (which should generally be the output
+ * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
+ * error.
+ */
+int odb_pack_keep(const char *name);
+
+const char *get_log_output_encoding(void);
+const char *get_commit_output_encoding(void);
+
+extern const char *git_commit_encoding;
+extern const char *git_log_output_encoding;
+
+extern const char *editor_program;
+extern const char *askpass_program;
+extern const char *excludes_file;
+
+/*
+ * Should we print an ellipsis after an abbreviated SHA-1 value
+ * when doing diff-raw output or indicating a detached HEAD?
+ */
+int print_sha1_ellipsis(void);
+
 #endif
index ac618641632f8c347b2a2900fb15b0de9ed8dd8a..7b525b1ecd896e02dfa71cdf3aab75496d998fac 100644 (file)
@@ -16,7 +16,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "ewok.h"
 
 #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))
index 6fe48d3ae0449a0298deb109b967ef3479ef0c47..8785cbc54a821cd2cb89ba0226a29a233d8c19ff 100644 (file)
@@ -19,7 +19,6 @@
 #include "git-compat-util.h"
 #include "ewok.h"
 #include "ewok_rlw.h"
-#include "cache.h"
 
 static inline size_t min_size(size_t a, size_t b)
 {
index 0232bbc99050a42db8c0de5513767d2c658a0398..1d597e84ea7f4c3c8296cbf527bf0c5514037e99 100644 (file)
@@ -1,7 +1,14 @@
-#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"
 
 #if defined(RUNTIME_PREFIX)
 
index 04016d1e3250f28ae6cd53a784913f02879769d8..26999e3b6591313a18df430170aaf935d2e24c14 100644 (file)
@@ -1,6 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "repository.h"
 #include "config.h"
+#include "date.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "refs.h"
 #include "pkt-line.h"
 #include "remote.h"
 #include "run-command.h"
 #include "connect.h"
+#include "trace2.h"
 #include "transport.h"
 #include "version.h"
 #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"
@@ -722,7 +728,7 @@ static void filter_refs(struct fetch_pack_args *args,
        *refs = newlist;
 }
 
-static void mark_alternate_complete(struct fetch_negotiator *unused,
+static void mark_alternate_complete(struct fetch_negotiator *negotiator UNUSED,
                                    struct object *obj)
 {
        mark_complete(&obj->oid);
@@ -762,9 +768,9 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
                if (!commit) {
                        struct object *o;
 
-                       if (!has_object_file_with_flags(&ref->old_oid,
-                                               OBJECT_INFO_QUICK |
-                                               OBJECT_INFO_SKIP_FETCH_OBJECT))
+                       if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid,
+                                                            OBJECT_INFO_QUICK |
+                                                            OBJECT_INFO_SKIP_FETCH_OBJECT))
                                continue;
                        o = parse_object(the_repository, &ref->old_oid);
                        if (!o || o->type != OBJ_COMMIT)
@@ -1094,7 +1100,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        struct ref *ref = copy_ref_list(orig_ref);
        struct object_id oid;
        const char *agent_feature;
-       int agent_len;
+       size_t agent_len;
        struct fetch_negotiator negotiator_alloc;
        struct fetch_negotiator *negotiator;
 
@@ -1112,7 +1118,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                agent_supported = 1;
                if (agent_len)
                        print_verbose(args, _("Server version is %.*s"),
-                                     agent_len, agent_feature);
+                                     (int)agent_len, agent_feature);
        }
 
        if (!server_supports("session-id"))
@@ -1853,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;
@@ -1875,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)
@@ -1904,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;
 }
 
@@ -1963,7 +1970,7 @@ static void update_shallow(struct fetch_pack_args *args,
                struct oid_array extra = OID_ARRAY_INIT;
                struct object_id *oid = si->shallow->oid;
                for (i = 0; i < si->shallow->nr; i++)
-                       if (has_object_file(&oid[i]))
+                       if (repo_has_object_file(the_repository, &oid[i]))
                                oid_array_append(&extra, &oid[i]);
                if (extra.nr) {
                        setup_alternate_shallow(&shallow_lock,
index f48f44f9cd1dbdd3aeafbe5a4bd3598e783d0e25..66e47449a092d67b66a172a0e325593d5e494efa 100644 (file)
@@ -1,8 +1,12 @@
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "diff.h"
 #include "diff-merges.h"
+#include "hex.h"
 #include "revision.h"
 #include "tag.h"
 #include "string-list.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)
 {
-       int status = 0;
-
        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)
@@ -37,10 +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 {
-               status = git_gpg_config(key, value, NULL);
-               if (status)
-                       return status;
-               return git_default_config(key, value, cb);
+               return git_default_config(key, value, ctx, cb);
        }
        return 0;
 }
@@ -271,9 +272,10 @@ static void record_person_from_buf(int which, struct string_list *people,
 static void record_person(int which, struct string_list *people,
                          struct commit *commit)
 {
-       const char *buffer = get_commit_buffer(commit, NULL);
+       const char *buffer = repo_get_commit_buffer(the_repository, commit,
+                                                   NULL);
        record_person_from_buf(which, people, buffer);
-       unuse_commit_buffer(commit, buffer);
+       repo_unuse_commit_buffer(the_repository, commit, buffer);
 }
 
 static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
@@ -384,7 +386,8 @@ static void shortlog(const char *name,
                if (subjects.nr > limit)
                        continue;
 
-               format_commit_message(commit, "%s", &sb, &ctx);
+               repo_format_commit_message(the_repository, commit, "%s", &sb,
+                                          &ctx);
                strbuf_ltrim(&sb);
 
                if (!sb.len)
@@ -506,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);
        }
 }
 
@@ -519,7 +523,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
                struct object_id *oid = origins.items[i].util;
                enum object_type type;
                unsigned long size;
-               char *buf = read_object_file(oid, &type, &size);
+               char *buf = repo_read_object_file(the_repository, oid, &type,
+                                                 &size);
                char *origbuf = buf;
                unsigned long len = size;
                struct signature_check sigc = { NULL };
@@ -551,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);
@@ -559,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);
@@ -605,7 +612,9 @@ static void find_merge_parents(struct merge_parents *result,
                 * util field yet.
                 */
                obj = parse_object(the_repository, &oid);
-               parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
+               parent = (struct commit *)repo_peel_to_type(the_repository,
+                                                           NULL, 0, obj,
+                                                           OBJ_COMMIT);
                if (!parent)
                        continue;
                commit_list_insert(parent, &parents);
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 2b18717ee805bc73aa50943731ac9a7212303d18..2b1e348005b7bcc7f27bc08e126c93260cda81e4 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -1,5 +1,9 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "date.h"
+#include "dir.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
 #include "object.h"
 #include "attr.h"
@@ -353,7 +357,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
        int result;
        const char *name;
 
-       if (parse_commit(commit))
+       if (repo_parse_commit(the_repository, commit))
                return -1;
 
        name = fsck_get_object_name(options, &commit->object.oid);
@@ -361,7 +365,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
                fsck_put_object_name(options, get_commit_tree_oid(commit),
                                     "%s:", name);
 
-       result = options->walk((struct object *)get_commit_tree(commit),
+       result = options->walk((struct object *) repo_get_commit_tree(the_repository, commit),
                               OBJ_TREE, data, options);
        if (result < 0)
                return result;
@@ -1160,7 +1164,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;
@@ -1233,7 +1239,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");
@@ -1302,9 +1309,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) {
@@ -1332,7 +1339,7 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
                if (oidset_contains(blobs_done, oid))
                        continue;
 
-               buf = read_object_file(oid, &type, &size);
+               buf = repo_read_object_file(the_repository, oid, &type, &size);
                if (!buf) {
                        if (is_promisor_object(oid))
                                continue;
@@ -1370,7 +1377,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) {
@@ -1391,7 +1399,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 668330880ef65f72ba4e9d38487152cc28c205a1..6359ba359bd24a5ece2fa4752d55f703af32388e 100644 (file)
--- a/fsck.h
+++ b/fsck.h
@@ -1,6 +1,7 @@
 #ifndef GIT_FSCK_H
 #define GIT_FSCK_H
 
+#include "object.h"
 #include "oidset.h"
 
 enum fsck_msg_type {
@@ -232,10 +233,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 e24838f9a86acc5de6980ac1c68d9d20421c3d42..70d776c54f6d142c2efd931cec140afaa91479f4 100644 (file)
@@ -3,7 +3,6 @@
 
 #ifdef HAVE_FSMONITOR_DAEMON_BACKEND
 
-#include "cache.h"
 #include "dir.h"
 #include "run-command.h"
 #include "simple-ipc.h"
index 19d772f0f3ae3737d70e69837ff0d9aa3021da62..88575aa54cad07312b2aa3dab3a87cfe0ebb3693 100644 (file)
@@ -1,7 +1,9 @@
-#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"
+#include "repository.h"
 #include "run-command.h"
 #include "strbuf.h"
 #include "trace2.h"
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 899bfe9c8138e1ae46f1fd0f0dfc7aebba05b81a..b62acf44aee2b9c029fac4389f6af7e4c4df6dab 100644 (file)
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "gettext.h"
 #include "repository.h"
 #include "fsmonitor-ipc.h"
 #include "fsmonitor-settings.h"
index a5b9e75437b5ec7d485eaba4795f21e53fb77122..f670c50937898342f693708c706a0db270be3a6d 100644 (file)
@@ -1,11 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "dir.h"
+#include "environment.h"
 #include "ewah/ewok.h"
 #include "fsmonitor.h"
 #include "fsmonitor-ipc.h"
 #include "run-command.h"
 #include "strbuf.h"
+#include "trace2.h"
 
 #define INDEX_EXTENSION_VERSION1       (1)
 #define INDEX_EXTENSION_VERSION2       (2)
index edf7ce5203b1a850e26c4b81cdb565350cd7f748..5195a8624db82b27f8fbb533675b35e841a2a44b 100644 (file)
@@ -1,54 +1,12 @@
 #ifndef FSMONITOR_H
 #define FSMONITOR_H
 
-#include "cache.h"
+#include "fsmonitor-ll.h"
 #include "dir.h"
 #include "fsmonitor-settings.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);
+#include "object.h"
+#include "read-cache-ll.h"
+#include "trace.h"
 
 /*
  * Check if refresh_fsmonitor has been called at least once.
@@ -86,7 +44,7 @@ static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache
            !(ce->ce_flags & CE_FSMONITOR_VALID)) {
                if (S_ISGITLINK(ce->ce_mode))
                        return;
-               istate->cache_changed = 1;
+               istate->cache_changed |= FSMONITOR_CHANGED;
                ce->ce_flags |= CE_FSMONITOR_VALID;
                trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_clean '%s'", ce->name);
        }
index e81357f9ba50a2a02ed2811b198a7039fcaaa46d..f27e94407b4c2848eecfbd827ee85525ff8c04ed 100644 (file)
--- a/gettext.c
+++ b/gettext.c
@@ -2,7 +2,9 @@
  * Copyright (c) 2010 Ævar Arnfjörð Bjarmason
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
 #include "exec-cmd.h"
 #include "gettext.h"
 #include "strbuf.h"
index 4f0028ce60ce44ca7febc1fe78dda77b5a793a01..3e7a59b5ff108dddce111cb372b6c846c093b4be 100644 (file)
@@ -339,6 +339,25 @@ static inline const char *precompose_string_if_needed(const char *in)
 int compat_mkdir_wo_trailing_slash(const char*, mode_t);
 #endif
 
+#ifdef time
+#undef time
+#endif
+static inline time_t git_time(time_t *tloc)
+{
+       struct timeval tv;
+
+       /*
+        * Avoid time(NULL), which can disagree with gettimeofday(2)
+        * and filesystem timestamps.
+        */
+       gettimeofday(&tv, NULL);
+
+       if (tloc)
+               *tloc = tv.tv_sec;
+       return tv.tv_sec;
+}
+#define time git_time
+
 #ifdef NO_STRUCT_ITIMERVAL
 struct itimerval {
        struct timeval it_interval;
@@ -403,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
@@ -421,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;
@@ -606,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);
@@ -660,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
@@ -691,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".
@@ -758,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);                               \
@@ -859,12 +850,6 @@ int git_lstat(const char *, struct stat *);
 #define pread git_pread
 ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
 #endif
-/*
- * Forward decl that will remind us if its twin in cache.h changes.
- * This function is used in compat/pread.c.  But we can't include
- * cache.h there.
- */
-ssize_t read_in_full(int fd, void *buf, size_t count);
 
 #ifdef NO_SETENV
 #define setenv gitsetenv
@@ -1066,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
@@ -1185,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;
@@ -1197,78 +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];
-#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
@@ -1287,6 +1250,25 @@ static inline int skip_iprefix(const char *str, const char *prefix,
        return 0;
 }
 
+/*
+ * Like skip_prefix_mem, but compare case-insensitively. Note that the
+ * comparison is done via tolower(), so it is strictly ASCII (no multi-byte
+ * characters or locale-specific conversions).
+ */
+static inline int skip_iprefix_mem(const char *buf, size_t len,
+                                  const char *prefix,
+                                  const char **out, size_t *outlen)
+{
+       do {
+               if (!*prefix) {
+                       *out = buf;
+                       *outlen = len;
+                       return 1;
+               }
+       } while (len-- > 0 && tolower(*buf++) == tolower(*prefix++));
+       return 0;
+}
+
 static inline int strtoul_ui(char const *s, int base, unsigned int *result)
 {
        unsigned long ul;
@@ -1426,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
@@ -1631,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 992124cc67ce579e89ae86e4cca42ba2c80ea1ea..e4e820e68095928765940be51fba0cdb8e5d609c 100755 (executable)
@@ -75,6 +75,11 @@ then
                merge_tool="$GIT_DIFF_TOOL"
        else
                merge_tool="$(get_merge_tool)"
+               subshell_exit_status=$?
+               if test $subshell_exit_status -gt 1
+               then
+                       exit $subshell_exit_status
+               fi
        fi
 fi
 
index 9f99201bcca1eada84c3f19d1ca44cb41b3f3c59..1ff26170ffcff8e3ebe768ecc946b1c7deb53949 100644 (file)
@@ -97,7 +97,42 @@ merge_mode () {
        test "$TOOL_MODE" = merge
 }
 
+get_gui_default () {
+       if diff_mode
+       then
+               GUI_DEFAULT_KEY="difftool.guiDefault"
+       else
+               GUI_DEFAULT_KEY="mergetool.guiDefault"
+       fi
+       GUI_DEFAULT_CONFIG_LCASE=$(git config --default false --get "$GUI_DEFAULT_KEY" | tr 'A-Z' 'a-z')
+       if test "$GUI_DEFAULT_CONFIG_LCASE" = "auto"
+       then
+               if test -n "$DISPLAY"
+               then
+                       GUI_DEFAULT=true
+               else
+                       GUI_DEFAULT=false
+               fi
+       else
+               GUI_DEFAULT=$(git config --default false --bool --get "$GUI_DEFAULT_KEY")
+               subshell_exit_status=$?
+               if test $subshell_exit_status -ne 0
+               then
+                       exit $subshell_exit_status
+               fi
+       fi
+       echo $GUI_DEFAULT
+}
+
 gui_mode () {
+       if test -z "$GIT_MERGETOOL_GUI"
+       then
+               GIT_MERGETOOL_GUI=$(get_gui_default)
+               if test $? -ne 0
+               then
+                       exit 2
+               fi
+       fi
        test "$GIT_MERGETOOL_GUI" = true
 }
 
@@ -467,6 +502,11 @@ get_merge_tool () {
        is_guessed=false
        # Check if a merge tool has been configured
        merge_tool=$(get_configured_merge_tool)
+       subshell_exit_status=$?
+       if test $subshell_exit_status -gt "1"
+       then
+               exit $subshell_exit_status
+       fi
        # Try to guess an appropriate merge tool if no tool has been set.
        if test -z "$merge_tool"
        then
index f751d9cfe2090485914559d467578e8a68cc823c..8a922893f75f220a8fce59a605405aceeaf91d7e 100755 (executable)
@@ -451,7 +451,7 @@ print_noop_and_exit () {
 
 main () {
        prompt=$(git config --bool mergetool.prompt)
-       GIT_MERGETOOL_GUI=false
+       GIT_MERGETOOL_GUI=
        guessed_merge_tool=false
        orderfile=
 
@@ -511,9 +511,14 @@ main () {
 
        if test -z "$merge_tool"
        then
-               if ! merge_tool=$(get_merge_tool)
+               merge_tool=$(get_merge_tool)
+               subshell_exit_status=$?
+               if test $subshell_exit_status = 1
                then
                        guessed_merge_tool=true
+               elif test $subshell_exit_status -gt 1
+               then
+                       exit $subshell_exit_status
                fi
        fi
        merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
index 07f2a0cbeaadd37f6ea13ee394a05257cdd3ae5d..288ea1ae802dcb88c582085de5a046178b6fbf5e 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>
@@ -87,8 +75,10 @@ git send-email --dump-aliases
 
   Automating:
     --identity              <str>  * Use the sendemail.<id> options.
-    --to-cmd                <str>  * Email To: via `<str> \$patch_path`
-    --cc-cmd                <str>  * Email Cc: via `<str> \$patch_path`
+    --to-cmd                <str>  * Email To: via `<str> \$patch_path`.
+    --cc-cmd                <str>  * Email Cc: via `<str> \$patch_path`.
+    --header-cmd            <str>  * Add headers via `<str> \$patch_path`.
+    --no-header-cmd                * Disable any header command in use.
     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
     --[no-]cc-cover                * Email Cc: addresses in the cover letter.
     --[no-]to-cover                * Email To: addresses in the cover letter.
@@ -202,7 +192,7 @@ my (@to,@cc,@xh,$envelope_sender,
        $author,$sender,$smtp_authpass,$annotate,$compose,$time);
 # Things we either get from config, *or* are overridden on the
 # command-line.
-my ($no_cc, $no_to, $no_bcc, $no_identity);
+my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);
 my (@config_to, @getopt_to);
 my (@config_cc, @getopt_cc);
 my (@config_bcc, @getopt_bcc);
@@ -269,7 +259,7 @@ sub do_edit {
 # Variables with corresponding config settings
 my ($suppress_from, $signed_off_by_cc);
 my ($cover_cc, $cover_to);
-my ($to_cmd, $cc_cmd);
+my ($to_cmd, $cc_cmd, $header_cmd);
 my ($smtp_server, $smtp_server_port, @smtp_server_options);
 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
 my ($batch_size, $relogin_delay);
@@ -318,6 +308,7 @@ my %config_settings = (
     "tocmd" => \$to_cmd,
     "cc" => \@config_cc,
     "cccmd" => \$cc_cmd,
+    "headercmd" => \$header_cmd,
     "aliasfiletype" => \$aliasfiletype,
     "bcc" => \@config_bcc,
     "suppresscc" => \@suppress_cc,
@@ -519,6 +510,8 @@ my %options = (
                    "compose" => \$compose,
                    "quiet" => \$quiet,
                    "cc-cmd=s" => \$cc_cmd,
+                   "header-cmd=s" => \$header_cmd,
+                   "no-header-cmd" => \$no_header_cmd,
                    "suppress-from!" => \$suppress_from,
                    "no-suppress-from" => sub {$suppress_from = 0},
                    "suppress-cc=s" => \@suppress_cc,
@@ -792,16 +785,46 @@ if (@rev_list_opts) {
                                    @rev_list_opts);
 }
 
-@files = handle_backup_files(@files);
+if (defined $sender) {
+       $sender =~ s/^\s+|\s+$//g;
+       ($sender) = expand_aliases($sender);
+} else {
+       $sender = $repoauthor->() || $repocommitter->() || '';
+}
+
+# $sender could be an already sanitized address
+# (e.g. sendemail.from could be manually sanitized by user).
+# But it's a no-op to run sanitize_address on an already sanitized address.
+$sender = sanitize_address($sender);
+
+$time = time - scalar $#files;
 
 if ($validate) {
+       # FIFOs can only be read once, exclude them from validation.
+       my @real_files = ();
        foreach my $f (@files) {
                unless (-p $f) {
-                       validate_patch($f, $target_xfer_encoding);
+                       push(@real_files, $f);
                }
        }
+
+       # Run the loop once again to avoid gaps in the counter due to FIFO
+       # arguments provided by the user.
+       my $num = 1;
+       my $num_files = scalar @real_files;
+       $ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
+       foreach my $r (@real_files) {
+               $ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
+               pre_process_file($r, 1);
+               validate_patch($r, $target_xfer_encoding);
+               $num += 1;
+       }
+       delete $ENV{GIT_SENDEMAIL_FILE_COUNTER};
+       delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
 }
 
+@files = handle_backup_files(@files);
+
 if (@files) {
        unless ($quiet) {
                print $_,"\n" for (@files);
@@ -936,17 +959,19 @@ EOT3
        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 {
@@ -1050,18 +1075,6 @@ if (!$force) {
        }
 }
 
-if (defined $sender) {
-       $sender =~ s/^\s+|\s+$//g;
-       ($sender) = expand_aliases($sender);
-} else {
-       $sender = $repoauthor->() || $repocommitter->() || '';
-}
-
-# $sender could be an already sanitized address
-# (e.g. sendemail.from could be manually sanitized by user).
-# But it's a no-op to run sanitize_address on an already sanitized address.
-$sender = sanitize_address($sender);
-
 my $to_whom = __("To whom should the emails be sent (if anyone)?");
 my $prompting = 0;
 if (!@initial_to && !defined $to_cmd) {
@@ -1153,10 +1166,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 {
@@ -1221,10 +1234,6 @@ sub make_message_id {
        #print "new message id = $message_id\n"; # Was useful for debugging
 }
 
-
-
-$time = time - scalar $#files;
-
 sub unquote_rfc2047 {
        local ($_) = @_;
        my $charset;
@@ -1502,16 +1511,7 @@ sub file_name_is_absolute {
        return File::Spec::Functions::file_name_is_absolute($path);
 }
 
-# Prepares the email, then asks the user what to do.
-#
-# If the user chooses to send the email, it's sent and 1 is returned.
-# If the user chooses not to send the email, 0 is returned.
-# If the user decides they want to make further edits, -1 is returned and the
-# caller is expected to call send_message again after the edits are performed.
-#
-# If an error occurs sending the email, this just dies.
-
-sub send_message {
+sub gen_header {
        my @recipients = unique_email_list(@to);
        @cc = (grep { my $cc = extract_valid_address_or_die($_);
                      not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
@@ -1537,7 +1537,7 @@ sub send_message {
 To: $to${ccline}
 Subject: $subject
 Date: $date
-Message-Id: $message_id
+Message-ID: $message_id
 ";
        if ($use_xmailer) {
                $header .= "X-Mailer: git-send-email $gitversion\n";
@@ -1553,6 +1553,22 @@ Message-Id: $message_id
        if (@xh) {
                $header .= join("\n", @xh) . "\n";
        }
+       my $recipients_ref = \@recipients;
+       return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
+}
+
+# Prepares the email, then asks the user what to do.
+#
+# If the user chooses to send the email, it's sent and 1 is returned.
+# If the user chooses not to send the email, 0 is returned.
+# If the user decides they want to make further edits, -1 is returned and the
+# caller is expected to call send_message again after the edits are performed.
+#
+# If an error occurs sending the email, this just dies.
+
+sub send_message {
+       my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
+       my @recipients = @$recipients_ref;
 
        my @sendmail_parameters = ('-i', @recipients);
        my $raw_from = $sender;
@@ -1742,11 +1758,8 @@ $in_reply_to = $initial_in_reply_to;
 $references = $initial_in_reply_to || '';
 $message_num = 0;
 
-# Prepares the email, prompts the user, sends it out
-# Returns 0 if an edit was done and the function should be called again, or 1
-# otherwise.
-sub process_file {
-       my ($t) = @_;
+sub pre_process_file {
+       my ($t, $quiet) = @_;
 
        open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
 
@@ -1765,16 +1778,17 @@ sub process_file {
        $subject = $initial_subject;
        $message = "";
        $message_num++;
-       # First unfold multiline header fields
+       undef $message_id;
+       # Retrieve and unfold header fields.
+       my @header_lines = ();
        while(<$fh>) {
                last if /^\s*$/;
-               if (/^\s+\S/ and @header) {
-                       chomp($header[$#header]);
-                       s/^\s+/ /;
-                       $header[$#header] .= $_;
-           } else {
-                       push(@header, $_);
-               }
+               push(@header_lines, $_);
+       }
+       @header = unfold_headers(@header_lines);
+       # Add computed headers, if applicable.
+       unless ($no_header_cmd || ! $header_cmd) {
+               push @header, invoke_header_cmd($header_cmd, $t);
        }
        # Now parse the header
        foreach(@header) {
@@ -1832,7 +1846,7 @@ sub process_file {
                                $has_mime_version = 1;
                                push @xh, $_;
                        }
-                       elsif (/^Message-Id: (.*)/i) {
+                       elsif (/^Message-ID: (.*)/i) {
                                $message_id = $1;
                        }
                        elsif (/^Content-Transfer-Encoding: (.*)/i) {
@@ -1900,9 +1914,9 @@ sub process_file {
        }
        close $fh;
 
-       push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
+       push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t, $quiet)
                if defined $to_cmd;
-       push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
+       push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t, $quiet)
                if defined $cc_cmd && !$suppress_cc{'cccmd'};
 
        if ($broken_encoding{$t} && !$has_content_type) {
@@ -1961,6 +1975,15 @@ sub process_file {
                        @initial_to = @to;
                }
        }
+}
+
+# Prepares the email, prompts the user, and sends it out
+# Returns 0 if an edit was done and the function should be called again, or 1
+# on the email being successfully sent out.
+sub process_file {
+       my ($t) = @_;
+
+        pre_process_file($t, $quiet);
 
        my $message_was_sent = send_message();
        if ($message_was_sent == -1) {
@@ -2006,15 +2029,64 @@ foreach my $t (@files) {
        }
 }
 
+# Execute a command and return its output lines as an array.  Blank
+# lines which do not appear at the end of the output are reported as
+# errors.
+sub execute_cmd {
+       my ($prefix, $cmd, $file) = @_;
+       my @lines = ();
+       my $seen_blank_line = 0;
+       open my $fh, "-|", "$cmd \Q$file\E"
+               or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
+       while (my $line = <$fh>) {
+               die sprintf(__("(%s) Malformed output from '%s'"), $prefix, $cmd)
+                   if $seen_blank_line;
+               if ($line =~ /^$/) {
+                       $seen_blank_line = $line =~ /^$/;
+                       next;
+               }
+               push @lines, $line;
+       }
+       close $fh
+           or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
+       return @lines;
+}
+
+# Process headers lines, unfolding multiline headers as defined by RFC
+# 2822.
+sub unfold_headers {
+       my @headers;
+       foreach(@_) {
+               last if /^\s*$/;
+               if (/^\s+\S/ and @headers) {
+                       chomp($headers[$#headers]);
+                       s/^\s+/ /;
+                       $headers[$#headers] .= $_;
+               } else {
+                       push(@headers, $_);
+               }
+       }
+       return @headers;
+}
+
+# Invoke the provided CMD with FILE as an argument, which should
+# output RFC 2822 email headers. Fold multiline headers and return the
+# headers as an array.
+sub invoke_header_cmd {
+       my ($cmd, $file) = @_;
+       my @lines = execute_cmd("header-cmd", $header_cmd, $file);
+       return unfold_headers(@lines);
+}
+
 # Execute a command (e.g. $to_cmd) to get a list of email addresses
 # and return a results array
 sub recipients_cmd {
-       my ($prefix, $what, $cmd, $file) = @_;
-
+       my ($prefix, $what, $cmd, $file, $quiet) = @_;
+       my @lines = ();
        my @addresses = ();
-       open my $fh, "-|", "$cmd \Q$file\E"
-           or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
-       while (my $address = <$fh>) {
+
+       @lines = execute_cmd($prefix, $cmd, $file);
+       for my $address (@lines) {
                $address =~ s/^\s*//g;
                $address =~ s/\s*$//g;
                $address = sanitize_address($address);
@@ -2023,8 +2095,6 @@ sub recipients_cmd {
                printf(__("(%s) Adding %s: %s from: '%s'\n"),
                       $prefix, $what, $address, $cmd) unless $quiet;
                }
-       close $fh
-           or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
        return @addresses;
 }
 
@@ -2095,10 +2165,21 @@ sub validate_patch {
                        chdir($repo->wc_path() or $repo->repo_path())
                                or die("chdir: $!");
                        local $ENV{"GIT_DIR"} = $repo->repo_path();
+
+                       my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
+
+                       require File::Temp;
+                       my ($header_filehandle, $header_filename) = File::Temp::tempfile(
+                            TEMPLATE => ".gitsendemail.header.XXXXXX",
+                            DIR => $repo->repo_path(),
+                            UNLINK => 1,
+                        );
+                       print $header_filehandle $header;
+
                        my @cmd = ("git", "hook", "run", "--ignore-missing",
                                    $hook_name, "--");
-                       my @cmd_msg = (@cmd, "<patch>");
-                       my @cmd_run = (@cmd, $target);
+                       my @cmd_msg = (@cmd, "<patch>", "<header>");
+                       my @cmd_run = (@cmd, $target, $header_filename);
                        $hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
                        chdir($cwd_save) or die("chdir: $!");
                }
similarity index 99%
rename from zlib.c
rename to git-zlib.c
index d594cba3fc9d82d94b9277e886f2bee265e552f6..d43bbeb6daa4c195048f7012e0bccff8c5b4b5f1 100644 (file)
--- a/zlib.c
@@ -2,7 +2,8 @@
  * zlib wrappers to make sure we don't silently miss errors
  * at init time.
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "git-zlib.h"
 
 static const char *zerr_to_string(int status)
 {
diff --git a/git-zlib.h b/git-zlib.h
new file mode 100644 (file)
index 0000000..d8a670a
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef GIT_ZLIB_H
+#define GIT_ZLIB_H
+
+typedef struct git_zstream {
+       z_stream z;
+       unsigned long avail_in;
+       unsigned long avail_out;
+       unsigned long total_in;
+       unsigned long total_out;
+       unsigned char *next_in;
+       unsigned char *next_out;
+} git_zstream;
+
+void git_inflate_init(git_zstream *);
+void git_inflate_init_gzip_only(git_zstream *);
+void git_inflate_end(git_zstream *);
+int git_inflate(git_zstream *, int flush);
+
+void git_deflate_init(git_zstream *, int level);
+void git_deflate_init_gzip(git_zstream *, int level);
+void git_deflate_init_raw(git_zstream *, int level);
+void git_deflate_end(git_zstream *);
+int git_deflate_abort(git_zstream *);
+int git_deflate_end_gently(git_zstream *);
+int git_deflate(git_zstream *, int flush);
+unsigned long git_deflate_bound(git_zstream *, unsigned long);
+
+#endif /* GIT_ZLIB_H */
diff --git a/git.c b/git.c
index 6171fd6769d715df1ce232bcac6d2465eca847dd..c67e44dd82d2e4fc01fb841c8f863282607f6ac7 100644 (file)
--- a/git.c
+++ b/git.c
@@ -1,10 +1,19 @@
 #include "builtin.h"
 #include "config.h"
+#include "environment.h"
 #include "exec-cmd.h"
+#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"
+#include "setup.h"
+#include "attr.h"
 #include "shallow.h"
+#include "trace.h"
+#include "trace2.h"
 
 #define RUN_SETUP              (1<<0)
 #define RUN_SETUP_GENTLY       (1<<1)
@@ -178,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;
@@ -307,6 +316,21 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        } else {
                                exit(list_cmds(cmd));
                        }
+               } else if (!strcmp(cmd, "--attr-source")) {
+                       if (*argc < 2) {
+                               fprintf(stderr, _("no attribute source given for --attr-source\n" ));
+                               usage(git_usage_string);
+                       }
+                       setenv(GIT_ATTR_SOURCE_ENVIRONMENT, (*argv)[1], 1);
+                       if (envchanged)
+                               *envchanged = 1;
+                       (*argv)++;
+                       (*argc)--;
+               } else if (skip_prefix(cmd, "--attr-source=", &cmd)) {
+                       set_git_attr_source(cmd);
+                       setenv(GIT_ATTR_SOURCE_ENVIRONMENT, cmd, 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else {
                        fprintf(stderr, _("unknown option: %s\n"), cmd);
                        usage(git_usage_string);
@@ -583,7 +607,7 @@ static struct cmd_struct commands[] = {
        { "show-branch", cmd_show_branch, RUN_SETUP },
        { "show-index", cmd_show_index, RUN_SETUP_GENTLY },
        { "show-ref", cmd_show_ref, RUN_SETUP },
-       { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
+       { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP },
        { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
        { "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
        { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
index 0ae7d685904b85f97a69b243e30f010671d050e3..df3ba2ea99b310c3cdcd5c7a8938eef498b3e92e 100755 (executable)
@@ -353,6 +353,16 @@ proc parseviewrevs {view revs} {
     return $ret
 }
 
+# Escapes a list of filter paths to be passed to git log via stdin. Note that
+# paths must not be quoted.
+proc escape_filter_paths {paths} {
+       set escaped [list]
+       foreach path $paths {
+               lappend escaped [string map {\\ \\\\ "\ " "\\\ "} $path]
+       }
+       return $escaped
+}
+
 # Start off a git log process and arrange to read its output
 proc start_rev_list {view} {
     global startmsecs commitidx viewcomplete curview
@@ -405,14 +415,17 @@ proc start_rev_list {view} {
         if {$revs eq {}} {
             return 0
         }
-        set args [concat $vflags($view) $revs]
+        set args $vflags($view)
     } else {
+        set revs {}
         set args $vorigargs($view)
     }
 
     if {[catch {
         set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
-                        --parents --boundary $args "--" $files] r]
+                        --parents --boundary $args --stdin \
+                        "<<[join [concat $revs "--" \
+                                [escape_filter_paths $files]] "\\n"]"] r]
     } err]} {
         error_popup "[mc "Error executing git log:"] $err"
         return 0
@@ -554,13 +567,20 @@ proc updatecommits {} {
             set revs $newrevs
             set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
         }
-        set args [concat $vflags($view) $revs --not $oldpos]
+        set args $vflags($view)
+        foreach r $oldpos {
+                lappend revs "^$r"
+        }
     } else {
+        set revs {}
         set args $vorigargs($view)
     }
     if {[catch {
         set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
-                        --parents --boundary $args "--" $vfilelimit($view)] r]
+                        --parents --boundary $args --stdin \
+                        "<<[join [concat $revs "--" \
+                                [escape_filter_paths \
+                                        $vfilelimit($view)]] "\\n"]"] r]
     } err]} {
         error_popup "[mc "Error executing git log:"] $err"
         return
@@ -10231,10 +10251,16 @@ proc getallcommits {} {
             foreach id $seeds {
                 lappend ids "^$id"
             }
+            lappend ids "--"
         }
     }
     if {$ids ne {}} {
-        set fd [open [concat $cmd $ids] r]
+        if {$ids eq "--all"} {
+            set cmd [concat $cmd "--all"]
+        } else {
+            set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"]
+        }
+        set fd [open $cmd r]
         fconfigure $fd -blocking 0
         incr allcommits
         nowbusy allcommits
index 5cd66d3a7864a443ed74ce0ae9e08b31673047c2..48f43c5a21d34569bdc966eefd652da38003d157 100644 (file)
@@ -1,13 +1,31 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "commit.h"
 #include "config.h"
+#include "date.h"
+#include "gettext.h"
 #include "run-command.h"
 #include "strbuf.h"
 #include "dir.h"
+#include "ident.h"
 #include "gpg-interface.h"
+#include "path.h"
 #include "sigchain.h"
 #include "tempfile.h"
 #include "alias.h"
+#include "environment.h"
+
+static int git_gpg_config(const char *, const char *,
+                         const struct config_context *, void *);
+
+static void gpg_interface_lazy_init(void)
+{
+       static int done;
+
+       if (done)
+               return;
+       done = 1;
+       git_config(git_gpg_config, NULL);
+}
 
 static char *configured_signing_key;
 static const char *ssh_default_key_command, *ssh_allowed_signers, *ssh_revocation_file;
@@ -569,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);
@@ -632,8 +650,10 @@ int check_signature(struct signature_check *sigc,
        struct gpg_format *fmt;
        int status;
 
+       gpg_interface_lazy_init();
+
        sigc->result = 'N';
-       sigc->trust_level = -1;
+       sigc->trust_level = TRUST_UNDEFINED;
 
        fmt = get_format_by_sig(signature);
        if (!fmt)
@@ -695,11 +715,15 @@ int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct
 
 void set_signing_key(const char *key)
 {
+       gpg_interface_lazy_init();
+
        free(configured_signing_key);
        configured_signing_key = xstrdup(key);
 }
 
-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;
@@ -888,6 +912,8 @@ static const char *get_ssh_key_id(void) {
 /* Returns a textual but unique representation of the signing key */
 const char *get_signing_key_id(void)
 {
+       gpg_interface_lazy_init();
+
        if (use_format->get_key_id) {
                return use_format->get_key_id();
        }
@@ -898,6 +924,8 @@ const char *get_signing_key_id(void)
 
 const char *get_signing_key(void)
 {
+       gpg_interface_lazy_init();
+
        if (configured_signing_key)
                return configured_signing_key;
        if (use_format->get_default_key) {
@@ -923,6 +951,8 @@ const char *gpg_trust_level_to_str(enum signature_trust_level level)
 
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
 {
+       gpg_interface_lazy_init();
+
        return use_format->sign_buffer(buffer, signature, signing_key);
 }
 
@@ -1025,7 +1055,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
                ssh_signing_key_file = strbuf_detach(&key_file->filename, NULL);
        } else {
                /* We assume a file */
-               ssh_signing_key_file = expand_user_path(signing_key, 1);
+               ssh_signing_key_file = interpolate_path(signing_key, 1);
        }
 
        buffer_file = mks_tempfile_t(".git_signing_buffer_tmpXXXXXX");
index 8a9ef41779e2fe91305dcb1b13cf66a282446cf6..143cdc1c02d4b31fa08f92fbcae1691c80d2c2d6 100644 (file)
@@ -79,7 +79,6 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
  */
 const char *gpg_trust_level_to_str(enum signature_trust_level level);
 
-int git_gpg_config(const char *, const char *, void *);
 void set_signing_key(const char *);
 const char *get_signing_key(void);
 
diff --git a/graph.c b/graph.c
index 568b6e7cd41512d17cc68e0595675ee858165164..2a9dc430fae105c8d6fb5a8763320ae40fb1e5c8 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
 #include "config.h"
 #include "commit.h"
 #include "color.h"
diff --git a/grep.c b/grep.c
index cee44a78d044dad174f5560b14432b396d6fdfb4..0904d55b244fb6f0e1b859cdd87be330c606d9e7 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "gettext.h"
 #include "grep.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "pretty.h"
 #include "userdiff.h"
 #include "xdiff-interface.h"
 #include "diff.h"
@@ -52,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;
@@ -87,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);
@@ -320,6 +324,15 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
        if (!opt->ignore_locale && is_utf8_locale() && !literal)
                options |= (PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_INVALID_UTF);
 
+#ifndef GIT_PCRE2_VERSION_10_35_OR_HIGHER
+       /*
+        * Work around a JIT bug related to invalid Unicode character handling
+        * fixed in 10.35:
+        * https://github.com/PCRE2Project/pcre2/commit/c21bd977547d
+        */
+       options &= ~PCRE2_UCP;
+#endif
+
 #ifndef GIT_PCRE2_VERSION_10_36_OR_HIGHER
        /* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
        if (PCRE2_MATCH_INVALID_UTF && options & (PCRE2_UTF | PCRE2_CASELESS))
diff --git a/grep.h b/grep.h
index 6075f997e68f5594f771123ae62655181278d38e..926c0875c42f63f961447a30f95c39d7ae031999 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -7,6 +7,9 @@
 #if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 36) || PCRE2_MAJOR >= 11
 #define GIT_PCRE2_VERSION_10_36_OR_HIGHER
 #endif
+#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 35) || PCRE2_MAJOR >= 11
+#define GIT_PCRE2_VERSION_10_35_OR_HIGHER
+#endif
 #if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 34) || PCRE2_MAJOR >= 11
 #define GIT_PCRE2_VERSION_10_34_OR_HIGHER
 #endif
@@ -199,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);
diff --git a/hash-ll.h b/hash-ll.h
new file mode 100644 (file)
index 0000000..10d84cc
--- /dev/null
+++ b/hash-ll.h
@@ -0,0 +1,309 @@
+#ifndef HASH_LL_H
+#define HASH_LL_H
+
+#if defined(SHA1_APPLE)
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(SHA1_OPENSSL)
+#  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 */
+#include "block-sha1/sha1.h"
+#endif
+
+#if defined(SHA256_NETTLE)
+#include "sha256/nettle.h"
+#elif defined(SHA256_GCRYPT)
+#define SHA256_NEEDS_CLONE_HELPER
+#include "sha256/gcrypt.h"
+#elif defined(SHA256_OPENSSL)
+#  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
+
+#ifndef platform_SHA_CTX
+/*
+ * platform's underlying implementation of SHA-1; could be OpenSSL,
+ * blk_SHA, Apple CommonCrypto, etc...  Note that the relevant
+ * SHA-1 header may have already defined platform_SHA_CTX for our
+ * own implementations like block-sha1, so we list
+ * the default for OpenSSL compatible SHA-1 implementations here.
+ */
+#define platform_SHA_CTX       SHA_CTX
+#define platform_SHA1_Init     SHA1_Init
+#define platform_SHA1_Update   SHA1_Update
+#define platform_SHA1_Final            SHA1_Final
+#endif
+
+#define git_SHA_CTX            platform_SHA_CTX
+#define git_SHA1_Init          platform_SHA1_Init
+#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 platform_SHA256_Update SHA256_Update
+#define platform_SHA256_Final  SHA256_Final
+#endif
+
+#define git_SHA256_CTX         platform_SHA256_CTX
+#define git_SHA256_Init                platform_SHA256_Init
+#define git_SHA256_Update      platform_SHA256_Update
+#define git_SHA256_Final       platform_SHA256_Final
+
+#ifdef platform_SHA256_Clone
+#define git_SHA256_Clone       platform_SHA256_Clone
+#endif
+
+#ifdef SHA1_MAX_BLOCK_SIZE
+#include "compat/sha1-chunked.h"
+#undef git_SHA1_Update
+#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)
+{
+       memcpy(dst, src, sizeof(*dst));
+}
+#endif
+
+/*
+ * Note that these constants are suitable for indexing the hash_algos array and
+ * comparing against each other, but are otherwise arbitrary, so they should not
+ * be exposed to the user or serialized to disk.  To know whether a
+ * git_hash_algo struct points to some usable hash function, test the format_id
+ * field for being non-zero.  Use the name field for user-visible situations and
+ * the format_id field for fixed-length fields on disk.
+ */
+/* An unknown hash function. */
+#define GIT_HASH_UNKNOWN 0
+/* SHA-1 */
+#define GIT_HASH_SHA1 1
+/* SHA-256  */
+#define GIT_HASH_SHA256 2
+/* Number of algorithms supported (including unknown). */
+#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
+
+/* "sha1", big-endian */
+#define GIT_SHA1_FORMAT_ID 0x73686131
+
+/* The length in bytes and in hex digits of an object name (SHA-1 value). */
+#define GIT_SHA1_RAWSZ 20
+#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
+/* The block size of SHA-1. */
+#define GIT_SHA1_BLKSZ 64
+
+/* "s256", big-endian */
+#define GIT_SHA256_FORMAT_ID 0x73323536
+
+/* The length in bytes and in hex digits of an object name (SHA-256 value). */
+#define GIT_SHA256_RAWSZ 32
+#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
+/* The block size of SHA-256. */
+#define GIT_SHA256_BLKSZ 64
+
+/* The length in byte and in hex digits of the largest possible hash value. */
+#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
+#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
+/* The largest possible block size for any supported hash. */
+#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
+
+struct object_id {
+       unsigned char hash[GIT_MAX_RAWSZ];
+       int algo;       /* XXX requires 4-byte alignment */
+};
+
+#define GET_OID_QUIETLY           01
+#define GET_OID_COMMIT            02
+#define GET_OID_COMMITTISH        04
+#define GET_OID_TREE             010
+#define GET_OID_TREEISH          020
+#define GET_OID_BLOB             040
+#define GET_OID_FOLLOW_SYMLINKS 0100
+#define GET_OID_RECORD_PATH     0200
+#define GET_OID_ONLY_TO_DIE    04000
+#define GET_OID_REQUIRE_PATH  010000
+
+#define GET_OID_DISAMBIGUATORS \
+       (GET_OID_COMMIT | GET_OID_COMMITTISH | \
+       GET_OID_TREE | GET_OID_TREEISH | \
+       GET_OID_BLOB)
+
+enum get_oid_result {
+       FOUND = 0,
+       MISSING_OBJECT = -1, /* The requested object is missing */
+       SHORT_NAME_AMBIGUOUS = -2,
+       /* The following only apply when symlinks are followed */
+       DANGLING_SYMLINK = -4, /*
+                               * The initial symlink is there, but
+                               * (transitively) points to a missing
+                               * in-tree file
+                               */
+       SYMLINK_LOOP = -5,
+       NOT_DIR = -6, /*
+                      * Somewhere along the symlink chain, a path is
+                      * requested which contains a file as a
+                      * non-final element.
+                      */
+};
+
+/* A suitably aligned type for stack allocations of hash contexts. */
+union git_hash_ctx {
+       git_SHA_CTX sha1;
+       git_SHA256_CTX sha256;
+};
+typedef union git_hash_ctx git_hash_ctx;
+
+typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
+typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
+typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
+typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
+typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
+
+struct git_hash_algo {
+       /*
+        * The name of the algorithm, as appears in the config file and in
+        * messages.
+        */
+       const char *name;
+
+       /* A four-byte version identifier, used in pack indices. */
+       uint32_t format_id;
+
+       /* The length of the hash in binary. */
+       size_t rawsz;
+
+       /* The length of the hash in hex characters. */
+       size_t hexsz;
+
+       /* The block size of the hash. */
+       size_t blksz;
+
+       /* The hash initialization function. */
+       git_hash_init_fn init_fn;
+
+       /* The hash context cloning function. */
+       git_hash_clone_fn clone_fn;
+
+       /* The hash update function. */
+       git_hash_update_fn update_fn;
+
+       /* The hash finalization function. */
+       git_hash_final_fn final_fn;
+
+       /* The hash finalization function for object IDs. */
+       git_hash_final_oid_fn final_oid_fn;
+
+       /* The OID of the empty tree. */
+       const struct object_id *empty_tree;
+
+       /* The OID of the empty blob. */
+       const struct object_id *empty_blob;
+
+       /* The all-zeros OID. */
+       const struct object_id *null_oid;
+};
+extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
+
+/*
+ * Return a GIT_HASH_* constant based on the name.  Returns GIT_HASH_UNKNOWN if
+ * the name doesn't match a known algorithm.
+ */
+int hash_algo_by_name(const char *name);
+/* Identical, except based on the format ID. */
+int hash_algo_by_id(uint32_t format_id);
+/* Identical, except based on the length. */
+int hash_algo_by_length(int len);
+/* Identical, except for a pointer to struct git_hash_algo. */
+static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
+{
+       return p - hash_algos;
+}
+
+const struct object_id *null_oid(void);
+
+static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
+{
+       /*
+        * Teach the compiler that there are only two possibilities of hash size
+        * here, so that it can optimize for this case as much as possible.
+        */
+       if (algop->rawsz == GIT_MAX_RAWSZ)
+               return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+       return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
+{
+       /*
+        * We write this here instead of deferring to hashcmp so that the
+        * compiler can properly inline it and avoid calling memcmp.
+        */
+       if (algop->rawsz == GIT_MAX_RAWSZ)
+               return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+       return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline void oidcpy(struct object_id *dst, const struct object_id *src)
+{
+       memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
+       dst->algo = src->algo;
+}
+
+static inline struct object_id *oiddup(const struct object_id *src)
+{
+       struct object_id *dst = xmalloc(sizeof(struct object_id));
+       oidcpy(dst, src);
+       return dst;
+}
+
+static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
+{
+       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);
+
+#endif
index b98ed5e11e8a3af02a99b6d2a977cc804a122414..9f0f95e2b9e0c44e79bfe6ee3ec43b61e7991f4a 100644 (file)
@@ -1,5 +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)
 {
diff --git a/hash.h b/hash.h
index 36b64165fc96375457415a6348eeebd2944c41f9..615ae0691d070b4bdc110fecad3a0c484d2b234c 100644 (file)
--- a/hash.h
+++ b/hash.h
 #ifndef HASH_H
 #define HASH_H
 
-#include "git-compat-util.h"
+#include "hash-ll.h"
 #include "repository.h"
 
-#if defined(SHA1_APPLE)
-#include <CommonCrypto/CommonDigest.h>
-#elif defined(SHA1_OPENSSL)
-#include <openssl/sha.h>
-#elif defined(SHA1_DC)
-#include "sha1dc_git.h"
-#else /* SHA1_BLK */
-#include "block-sha1/sha1.h"
-#endif
-
-#if defined(SHA256_NETTLE)
-#include "sha256/nettle.h"
-#elif defined(SHA256_GCRYPT)
-#define SHA256_NEEDS_CLONE_HELPER
-#include "sha256/gcrypt.h"
-#elif defined(SHA256_OPENSSL)
-#include <openssl/sha.h>
-#else
-#include "sha256/block/sha256.h"
-#endif
-
-#ifndef platform_SHA_CTX
-/*
- * platform's underlying implementation of SHA-1; could be OpenSSL,
- * blk_SHA, Apple CommonCrypto, etc...  Note that the relevant
- * SHA-1 header may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1, so we list
- * the default for OpenSSL compatible SHA-1 implementations here.
- */
-#define platform_SHA_CTX       SHA_CTX
-#define platform_SHA1_Init     SHA1_Init
-#define platform_SHA1_Update   SHA1_Update
-#define platform_SHA1_Final            SHA1_Final
-#endif
-
-#define git_SHA_CTX            platform_SHA_CTX
-#define git_SHA1_Init          platform_SHA1_Init
-#define git_SHA1_Update                platform_SHA1_Update
-#define git_SHA1_Final         platform_SHA1_Final
-
-#ifndef platform_SHA256_CTX
-#define platform_SHA256_CTX    SHA256_CTX
-#define platform_SHA256_Init   SHA256_Init
-#define platform_SHA256_Update SHA256_Update
-#define platform_SHA256_Final  SHA256_Final
-#endif
-
-#define git_SHA256_CTX         platform_SHA256_CTX
-#define git_SHA256_Init                platform_SHA256_Init
-#define git_SHA256_Update      platform_SHA256_Update
-#define git_SHA256_Final       platform_SHA256_Final
-
-#ifdef platform_SHA256_Clone
-#define git_SHA256_Clone       platform_SHA256_Clone
-#endif
-
-#ifdef SHA1_MAX_BLOCK_SIZE
-#include "compat/sha1-chunked.h"
-#undef git_SHA1_Update
-#define git_SHA1_Update                git_SHA1_Update_Chunked
-#endif
-
-static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
-{
-       memcpy(dst, src, sizeof(*dst));
-}
-
-#ifndef SHA256_NEEDS_CLONE_HELPER
-static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
-{
-       memcpy(dst, src, sizeof(*dst));
-}
-#endif
-
-/*
- * Note that these constants are suitable for indexing the hash_algos array and
- * comparing against each other, but are otherwise arbitrary, so they should not
- * be exposed to the user or serialized to disk.  To know whether a
- * git_hash_algo struct points to some usable hash function, test the format_id
- * field for being non-zero.  Use the name field for user-visible situations and
- * the format_id field for fixed-length fields on disk.
- */
-/* An unknown hash function. */
-#define GIT_HASH_UNKNOWN 0
-/* SHA-1 */
-#define GIT_HASH_SHA1 1
-/* SHA-256  */
-#define GIT_HASH_SHA256 2
-/* Number of algorithms supported (including unknown). */
-#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
-
-/* "sha1", big-endian */
-#define GIT_SHA1_FORMAT_ID 0x73686131
-
-/* The length in bytes and in hex digits of an object name (SHA-1 value). */
-#define GIT_SHA1_RAWSZ 20
-#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
-/* The block size of SHA-1. */
-#define GIT_SHA1_BLKSZ 64
-
-/* "s256", big-endian */
-#define GIT_SHA256_FORMAT_ID 0x73323536
-
-/* The length in bytes and in hex digits of an object name (SHA-256 value). */
-#define GIT_SHA256_RAWSZ 32
-#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
-/* The block size of SHA-256. */
-#define GIT_SHA256_BLKSZ 64
-
-/* The length in byte and in hex digits of the largest possible hash value. */
-#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
-#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
-/* The largest possible block size for any supported hash. */
-#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
-
-struct object_id {
-       unsigned char hash[GIT_MAX_RAWSZ];
-       int algo;       /* XXX requires 4-byte alignment */
-};
-
-/* A suitably aligned type for stack allocations of hash contexts. */
-union git_hash_ctx {
-       git_SHA_CTX sha1;
-       git_SHA256_CTX sha256;
-};
-typedef union git_hash_ctx git_hash_ctx;
-
-typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
-typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
-typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
-typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
-typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
-
-struct git_hash_algo {
-       /*
-        * The name of the algorithm, as appears in the config file and in
-        * messages.
-        */
-       const char *name;
-
-       /* A four-byte version identifier, used in pack indices. */
-       uint32_t format_id;
-
-       /* The length of the hash in binary. */
-       size_t rawsz;
-
-       /* The length of the hash in hex characters. */
-       size_t hexsz;
-
-       /* The block size of the hash. */
-       size_t blksz;
-
-       /* The hash initialization function. */
-       git_hash_init_fn init_fn;
-
-       /* The hash context cloning function. */
-       git_hash_clone_fn clone_fn;
-
-       /* The hash update function. */
-       git_hash_update_fn update_fn;
-
-       /* The hash finalization function. */
-       git_hash_final_fn final_fn;
-
-       /* The hash finalization function for object IDs. */
-       git_hash_final_oid_fn final_oid_fn;
-
-       /* The OID of the empty tree. */
-       const struct object_id *empty_tree;
-
-       /* The OID of the empty blob. */
-       const struct object_id *empty_blob;
-
-       /* The all-zeros OID. */
-       const struct object_id *null_oid;
-};
-extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
-
-/*
- * Return a GIT_HASH_* constant based on the name.  Returns GIT_HASH_UNKNOWN if
- * the name doesn't match a known algorithm.
- */
-int hash_algo_by_name(const char *name);
-/* Identical, except based on the format ID. */
-int hash_algo_by_id(uint32_t format_id);
-/* Identical, except based on the length. */
-int hash_algo_by_length(int len);
-/* Identical, except for a pointer to struct git_hash_algo. */
-static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
-{
-       return p - hash_algos;
-}
-
 #define the_hash_algo the_repository->hash_algo
 
-const struct object_id *null_oid(void);
-
-static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
-{
-       /*
-        * Teach the compiler that there are only two possibilities of hash size
-        * here, so that it can optimize for this case as much as possible.
-        */
-       if (algop->rawsz == GIT_MAX_RAWSZ)
-               return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
-       return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
 static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
 {
        return hashcmp_algop(sha1, sha2, the_hash_algo);
@@ -227,17 +21,6 @@ static inline int oidcmp(const struct object_id *oid1, const struct object_id *o
        return hashcmp_algop(oid1->hash, oid2->hash, algop);
 }
 
-static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
-{
-       /*
-        * We write this here instead of deferring to hashcmp so that the
-        * compiler can properly inline it and avoid calling memcmp.
-        */
-       if (algop->rawsz == GIT_MAX_RAWSZ)
-               return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
-       return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
 static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
 {
        return hasheq_algop(sha1, sha2, the_hash_algo);
@@ -263,12 +46,6 @@ static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
        memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
 }
 
-static inline void oidcpy(struct object_id *dst, const struct object_id *src)
-{
-       memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
-       dst->algo = src->algo;
-}
-
 /* Like oidcpy() but zero-pads the unused bytes in dst's hash array. */
 static inline void oidcpy_with_padding(struct object_id *dst,
                                       const struct object_id *src)
@@ -285,13 +62,6 @@ static inline void oidcpy_with_padding(struct object_id *dst,
        dst->algo = src->algo;
 }
 
-static inline struct object_id *oiddup(const struct object_id *src)
-{
-       struct object_id *dst = xmalloc(sizeof(struct object_id));
-       oidcpy(dst, src);
-       return dst;
-}
-
 static inline void hashclr(unsigned char *hash)
 {
        memset(hash, 0, the_hash_algo->rawsz);
@@ -329,12 +99,4 @@ static inline int is_empty_tree_oid(const struct object_id *oid)
        return oideq(oid, the_hash_algo->empty_tree);
 }
 
-static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
-{
-       oid->algo = hash_algo_by_ptr(algop);
-}
-
-const char *empty_tree_oid_hex(void);
-const char *empty_blob_oid_hex(void);
-
 #endif
index cf5fea87eb02bf753d408f1eeb00f5de2a02e907..ee45ef00852c86b5f0fe0de8177c806c53d7efa0 100644 (file)
--- a/hashmap.c
+++ b/hashmap.c
@@ -1,7 +1,7 @@
 /*
  * Generic implementation of hash-based key value mappings.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "hashmap.h"
 
 #define FNV32_BASE ((unsigned int) 0x811c9dc5)
index 7251687d730d608437a8ed24e4551cf9344fd7f4..c8216e47bb21171a59cdcc1f17b600ae60699dfa 100644 (file)
--- a/hashmap.h
+++ b/hashmap.h
@@ -1,8 +1,6 @@
 #ifndef HASHMAP_H
 #define HASHMAP_H
 
-#include "hash.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.
@@ -270,7 +249,7 @@ void hashmap_clear_(struct hashmap *map, ssize_t offset);
 #define hashmap_clear(map) hashmap_clear_(map, -1)
 
 /*
- * Similar to hashmap_clear(), except that the table is no deallocated; it
+ * Similar to hashmap_clear(), except that the table is not deallocated; it
  * is merely zeroed out but left the same size as before.  If the hashmap
  * will be reused, this avoids the overhead of deallocating and
  * reallocating map->table.  As with hashmap_clear(), you may need to free
diff --git a/help.c b/help.c
index 812af4cdea62129c12ec33813d934d677c61d714..6d2ebfbd2a45f134bc45c039cb4cf26b402b8f6c 100644 (file)
--- a/help.c
+++ b/help.c
@@ -1,9 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "builtin.h"
 #include "exec-cmd.h"
 #include "run-command.h"
 #include "levenshtein.h"
+#include "gettext.h"
 #include "help.h"
 #include "command-list.h"
 #include "string-list.h"
@@ -307,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;
 
@@ -457,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;
 
@@ -540,7 +543,9 @@ static struct cmdnames aliases;
 #define AUTOCORRECT_NEVER (-2)
 #define AUTOCORRECT_IMMEDIATELY (-1)
 
-static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
+static int git_unknown_cmd_config(const char *var, const char *value,
+                                 const struct config_context *ctx,
+                                 void *cb UNUSED)
 {
        const char *p;
 
@@ -554,7 +559,7 @@ static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
                } 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.c b/hex.c
index 4f64d34696379d35e7ace281a5d471f55f1737ad..01f17fe5c906e6f8dd225b7c07bfb725a54a48a8 100644 (file)
--- a/hex.c
+++ b/hex.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash.h"
+#include "hex.h"
 
 const signed char hexval_table[256] = {
         -1, -1, -1, -1, -1, -1, -1, -1,                /* 00-07 */
@@ -61,7 +63,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
new file mode 100644 (file)
index 0000000..87abf66
--- /dev/null
+++ b/hex.h
@@ -0,0 +1,86 @@
+#ifndef HEX_H
+#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]);
+}
+
+/*
+ * 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_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,
+ * and writes the NUL-terminated output to the buffer `out`, which must be at
+ * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
+ * convenience.
+ *
+ * The non-`_r` variant returns a static buffer, but uses a ring of 4
+ * buffers, making it safe to make multiple calls for a single statement, like:
+ *
+ *   printf("%s -> %s", hash_to_hex(one), hash_to_hex(two));
+ *   printf("%s -> %s", oid_to_hex(one), oid_to_hex(two));
+ */
+char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
+char *oid_to_hex_r(char *out, const struct object_id *oid);
+char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *);      /* static buffer result! */
+char *hash_to_hex(const unsigned char *hash);                                          /* same static buffer */
+char *oid_to_hex(const struct object_id *oid);                                         /* same static buffer */
+
+/*
+ * Parse a 40-character hexadecimal object ID starting from hex, updating the
+ * pointer specified by end when parsing stops.  The resulting object ID is
+ * stored in oid.  Returns 0 on success.  Parsing will stop on the first NUL or
+ * other invalid character.  end is only updated on success; otherwise, it is
+ * unmodified.
+ */
+int parse_oid_hex(const char *hex, struct object_id *oid, const char **end);
+
+/* Like parse_oid_hex, but for an arbitrary hash algorithm. */
+int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end,
+                       const struct git_hash_algo *algo);
+
+
+/*
+ * These functions work like get_oid_hex and parse_oid_hex, but they will parse
+ * a hex value for any algorithm. The algorithm is detected based on the length
+ * and the algorithm in use is returned. If this is not a hex object ID in any
+ * algorithm, returns GIT_HASH_UNKNOWN.
+ */
+int get_oid_hex_any(const char *hex, struct object_id *oid);
+int parse_oid_hex_any(const char *hex, struct object_id *oid, const char **end);
+
+#endif
diff --git a/hook.c b/hook.c
index 1a8483186349b00608d40bc3d8702aa39ffb79c8..f6306d72b31879705977a023a7865c3f1677404c 100644 (file)
--- a/hook.c
+++ b/hook.c
@@ -1,7 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
+#include "gettext.h"
 #include "hook.h"
+#include "path.h"
 #include "run-command.h"
 #include "config.h"
+#include "strbuf.h"
 
 const char *find_hook(const char *name)
 {
@@ -43,9 +48,9 @@ int hook_exists(const char *name)
 }
 
 static int pick_next_hook(struct child_process *cp,
-                         struct strbuf *out,
+                         struct strbuf *out UNUSED,
                          void *pp_cb,
-                         void **pp_task_cb)
+                         void **pp_task_cb UNUSED)
 {
        struct hook_cb_data *hook_cb = pp_cb;
        const char *hook_path = hook_cb->hook_path;
@@ -77,9 +82,9 @@ static int pick_next_hook(struct child_process *cp,
        return 1;
 }
 
-static int notify_start_failure(struct strbuf *out,
+static int notify_start_failure(struct strbuf *out UNUSED,
                                void *pp_cb,
-                               void *pp_task_cp)
+                               void *pp_task_cp UNUSED)
 {
        struct hook_cb_data *hook_cb = pp_cb;
 
@@ -89,9 +94,9 @@ static int notify_start_failure(struct strbuf *out,
 }
 
 static int notify_hook_finished(int result,
-                               struct strbuf *out,
+                               struct strbuf *out UNUSED,
                                void *pp_cb,
-                               void *pp_task_cb)
+                               void *pp_task_cb UNUSED)
 {
        struct hook_cb_data *hook_cb = pp_cb;
        struct run_hooks_opt *opt = hook_cb->options;
index 8ab58e55f8524851fa77e047e9b9a5dfd31eb6bd..ff07b87e6461446610c35708a39f22a5e5b36aff 100644 (file)
@@ -1,5 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.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 "write-or-die.h"
 
 static const char content_type[] = "Content-Type";
 static const char content_length[] = "Content-Length";
@@ -524,7 +529,7 @@ static int show_text_ref(const char *name, const struct object_id *oid,
        return 0;
 }
 
-static void get_info_refs(struct strbuf *hdr, char *arg)
+static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
 {
        const char *service_name = get_parameter("service");
        struct strbuf buf = STRBUF_INIT;
@@ -553,7 +558,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg)
 
        } 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);
@@ -578,7 +583,7 @@ static int show_head_ref(const char *refname, const struct object_id *oid,
        return 0;
 }
 
-static void get_head(struct strbuf *hdr, char *arg)
+static void get_head(struct strbuf *hdr, char *arg UNUSED)
 {
        struct strbuf buf = STRBUF_INIT;
 
@@ -588,7 +593,7 @@ static void get_head(struct strbuf *hdr, char *arg)
        strbuf_release(&buf);
 }
 
-static void get_info_packs(struct strbuf *hdr, char *arg)
+static void get_info_packs(struct strbuf *hdr, char *arg UNUSED)
 {
        size_t objdirlen = strlen(get_object_directory());
        struct strbuf buf = STRBUF_INIT;
@@ -736,7 +741,7 @@ static int bad_request(struct strbuf *hdr, const struct service_cmd *c)
        return 0;
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
 {
        char *method = getenv("REQUEST_METHOD");
        const char *proto_header;
index 258fec2068262c815ae68b08c8729b0bc60ee498..fffda592670e667e81eb92af218f9a4d95d7614d 100644 (file)
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "exec-cmd.h"
+#include "gettext.h"
+#include "hex.h"
 #include "http.h"
 #include "walker.h"
+#include "setup.h"
 #include "strvec.h"
 #include "urlmatch.h"
 #include "trace2.h"
index 7f71316456c6832daa28bfc054f53b3224bf970f..a704f490fdb2c2144b47a5629ed9ee0643ab0d83 100644 (file)
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "hex.h"
 #include "repository.h"
 #include "commit.h"
 #include "tag.h"
 #include "exec-cmd.h"
 #include "remote.h"
 #include "list-objects.h"
+#include "setup.h"
 #include "sigchain.h"
 #include "strvec.h"
+#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
@@ -362,7 +367,8 @@ static void start_put(struct transfer_request *request)
        ssize_t size;
        git_zstream stream;
 
-       unpacked = read_object_file(&request->obj->oid, &type, &len);
+       unpacked = repo_read_object_file(the_repository, &request->obj->oid,
+                                        &type, &len);
        hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
 
        /* Set it up */
@@ -601,7 +607,7 @@ static void finish_request(struct transfer_request *request)
 }
 
 static int is_running_queue;
-static int fill_active_slot(void *unused)
+static int fill_active_slot(void *data UNUSED)
 {
        struct transfer_request *request;
 
@@ -777,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, ':');
@@ -1331,7 +1337,8 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
        int count = 0;
 
        while ((commit = get_revision(revs)) != NULL) {
-               p = process_tree(get_commit_tree(commit), p);
+               p = process_tree(repo_get_commit_tree(the_repository, commit),
+                                p);
                commit->object.flags |= LOCAL;
                if (!(commit->object.flags & UNINTERESTING))
                        count += add_send_request(&commit->object, lock);
@@ -1426,7 +1433,7 @@ static void one_remote_ref(const char *refname)
         * Fetch a copy of the object if it doesn't exist locally - it
         * may be required for updating server info later.
         */
-       if (repo->can_update_info_refs && !has_object_file(&ref->old_oid)) {
+       if (repo->can_update_info_refs && !repo_has_object_file(the_repository, &ref->old_oid)) {
                obj = lookup_unknown_object(the_repository, &ref->old_oid);
                fprintf(stderr, "  fetch %s for %s\n",
                        oid_to_hex(&ref->old_oid), refname);
@@ -1570,7 +1577,7 @@ static int verify_merge_base(struct object_id *head_oid, struct ref *remote)
        struct commit *branch = lookup_commit_or_die(&remote->old_oid,
                                                     remote->name);
 
-       return in_merge_bases(branch, head);
+       return repo_in_merge_bases(the_repository, branch, head);
 }
 
 static int delete_remote_branch(const char *pattern, int force)
@@ -1627,14 +1634,14 @@ static int delete_remote_branch(const char *pattern, int force)
                        return error("Remote HEAD symrefs too deep");
                if (is_null_oid(&head_oid))
                        return error("Unable to resolve remote HEAD");
-               if (!has_object_file(&head_oid))
+               if (!repo_has_object_file(the_repository, &head_oid))
                        return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", oid_to_hex(&head_oid));
 
                /* Remote branch must resolve to a known object */
                if (is_null_oid(&remote_ref->old_oid))
                        return error("Unable to resolve remote branch %s",
                                     remote_ref->name);
-               if (!has_object_file(&remote_ref->old_oid))
+               if (!repo_has_object_file(the_repository, &remote_ref->old_oid))
                        return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, oid_to_hex(&remote_ref->old_oid));
 
                /* Remote branch must be an ancestor of remote HEAD */
@@ -1854,7 +1861,7 @@ int cmd_main(int argc, const char **argv)
                if (!force_all &&
                    !is_null_oid(&ref->old_oid) &&
                    !ref->force) {
-                       if (!has_object_file(&ref->old_oid) ||
+                       if (!repo_has_object_file(the_repository, &ref->old_oid) ||
                            !ref_newer(&ref->peer_ref->new_oid,
                                       &ref->old_oid)) {
                                /*
index b8f0f98ae146999adf3770cc7338cbacbbbf8cb3..78d99f7c4b002cb95196800a62a1de8fbcce6cea 100644 (file)
@@ -1,12 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "repository.h"
 #include "commit.h"
+#include "hex.h"
 #include "walker.h"
 #include "http.h"
 #include "list.h"
 #include "transport.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 struct alt_base {
        char *base;
@@ -52,8 +53,7 @@ static void fetch_alternates(struct walker *walker, const char *base);
 
 static void process_object_response(void *callback_data);
 
-static void start_object_request(struct walker *walker,
-                                struct object_request *obj_req)
+static void start_object_request(struct object_request *obj_req)
 {
        struct active_request_slot *slot;
        struct http_object_request *req;
@@ -110,7 +110,7 @@ static void process_object_response(void *callback_data)
                        obj_req->repo =
                                obj_req->repo->next;
                        release_http_object_request(obj_req->req);
-                       start_object_request(walker, obj_req);
+                       start_object_request(obj_req);
                        return;
                }
        }
@@ -127,7 +127,7 @@ static void release_object_request(struct object_request *obj_req)
        free(obj_req);
 }
 
-static int fill_active_slot(struct walker *walker)
+static int fill_active_slot(void *data UNUSED)
 {
        struct object_request *obj_req;
        struct list_head *pos, *tmp, *head = &object_queue_head;
@@ -135,10 +135,10 @@ static int fill_active_slot(struct walker *walker)
        list_for_each_safe(pos, tmp, head) {
                obj_req = list_entry(pos, struct object_request, node);
                if (obj_req->state == WAITING) {
-                       if (has_object_file(&obj_req->oid))
+                       if (repo_has_object_file(the_repository, &obj_req->oid))
                                obj_req->state = COMPLETE;
                        else {
-                               start_object_request(walker, obj_req);
+                               start_object_request(obj_req);
                                return 1;
                        }
                }
@@ -492,7 +492,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
        if (!obj_req)
                return error("Couldn't find request for %s in the queue", hex);
 
-       if (has_object_file(&obj_req->oid)) {
+       if (repo_has_object_file(the_repository, &obj_req->oid)) {
                if (obj_req->req)
                        abort_http_object_request(obj_req->req);
                abort_object_request(obj_req);
@@ -613,7 +613,7 @@ struct walker *get_http_walker(const char *url)
        walker->cleanup = cleanup;
        walker->data = data;
 
-       add_fill_function(walker, (int (*)(void *)) fill_active_slot);
+       add_fill_function(NULL, fill_active_slot);
 
        return walker;
 }
diff --git a/http.c b/http.c
index c4b6ddef287b90f6492706cdaa483c1832d8b06c..8f71bf00d8998af44e177a86d73dbc86872c9726 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "git-curl-compat.h"
+#include "hex.h"
 #include "http.h"
 #include "config.h"
 #include "pack.h"
 #include "version.h"
 #include "pkt-line.h"
 #include "gettext.h"
+#include "trace.h"
 #include "transport.h"
 #include "packfile.h"
 #include "protocol.h"
 #include "string-list.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 
 static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
 static int trace_curl_data = 1;
@@ -39,6 +42,7 @@ static int curl_ssl_verify = -1;
 static int curl_ssl_try;
 static const char *curl_http_version = NULL;
 static const char *ssl_cert;
+static const char *ssl_cert_type;
 static const char *ssl_cipherlist;
 static const char *ssl_version;
 static struct {
@@ -58,6 +62,7 @@ static struct {
 #endif
 };
 static const char *ssl_key;
+static const char *ssl_key_type;
 static const char *ssl_capath;
 static const char *curl_no_proxy;
 #ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
@@ -181,7 +186,117 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
        return nmemb;
 }
 
-size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
+/*
+ * A folded header continuation line starts with any number of spaces or
+ * horizontal tab characters (SP or HTAB) as per RFC 7230 section 3.2.
+ * It is not a continuation line if the line starts with any other character.
+ */
+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 UNUSED)
+{
+       size_t size = eltsize * nmemb;
+       struct strvec *values = &http_auth.wwwauth_headers;
+       struct strbuf buf = STRBUF_INIT;
+       const char *val;
+       size_t val_len;
+
+       /*
+        * Header lines may not come NULL-terminated from libcurl so we must
+        * limit all scans to the maximum length of the header line, or leverage
+        * strbufs for all operations.
+        *
+        * In addition, it is possible that header values can be split over
+        * multiple lines as per RFC 7230. 'Line folding' has been deprecated
+        * but older servers may still emit them. A continuation header field
+        * value is identified as starting with a space or horizontal tab.
+        *
+        * The formal definition of a header field as given in RFC 7230 is:
+        *
+        * header-field   = field-name ":" OWS field-value OWS
+        *
+        * field-name     = token
+        * field-value    = *( field-content / obs-fold )
+        * field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+        * field-vchar    = VCHAR / obs-text
+        *
+        * obs-fold       = CRLF 1*( SP / HTAB )
+        *                ; obsolete line folding
+        *                ; see Section 3.2.4
+        */
+
+       /* Start of a new WWW-Authenticate header */
+       if (skip_iprefix_mem(ptr, size, "www-authenticate:", &val, &val_len)) {
+               strbuf_add(&buf, val, val_len);
+
+               /*
+                * Strip the CRLF that should be present at the end of each
+                * field as well as any trailing or leading whitespace from the
+                * value.
+                */
+               strbuf_trim(&buf);
+
+               strvec_push(values, buf.buf);
+               http_auth.header_is_last_match = 1;
+               goto exit;
+       }
+
+       /*
+        * This line could be a continuation of the previously matched header
+        * field. If this is the case then we should append this value to the
+        * end of the previously consumed value.
+        */
+       if (http_auth.header_is_last_match && is_hdr_continuation(ptr, size)) {
+               /*
+                * Trim the CRLF and any leading or trailing from this line.
+                */
+               strbuf_add(&buf, ptr, size);
+               strbuf_trim(&buf);
+
+               /*
+                * At this point we should always have at least one existing
+                * value, even if it is empty. Do not bother appending the new
+                * value if this continuation header is itself empty.
+                */
+               if (!values->nr) {
+                       BUG("should have at least one existing header value");
+               } else if (buf.len) {
+                       char *prev = xstrdup(values->v[values->nr - 1]);
+
+                       /* Join two non-empty values with a single space. */
+                       const char *const sp = *prev ? " " : "";
+
+                       strvec_pop(values);
+                       strvec_pushf(values, "%s%s%s", prev, sp, buf.buf);
+                       free(prev);
+               }
+
+               goto exit;
+       }
+
+       /* Not a continuation of a previously matched auth header line. */
+       http_auth.header_is_last_match = 0;
+
+       /*
+        * If this is a HTTP status line and not a header field, this signals
+        * a different HTTP response. libcurl writes all the output of all
+        * response headers of all responses, including redirects.
+        * We only care about the last HTTP request response's headers so clear
+        * the existing array.
+        */
+       if (skip_iprefix_mem(ptr, size, "http/", &val, &val_len))
+               strvec_clear(values);
+
+exit:
+       strbuf_release(&buf);
+       return size;
+}
+
+size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
+                  void *data UNUSED)
 {
        return nmemb;
 }
@@ -249,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);
@@ -264,8 +380,12 @@ static int http_options(const char *var, const char *value, void *cb)
                return git_config_string(&ssl_version, var, value);
        if (!strcmp("http.sslcert", var))
                return git_config_pathname(&ssl_cert, var, value);
+       if (!strcmp("http.sslcerttype", var))
+               return git_config_string(&ssl_cert_type, var, value);
        if (!strcmp("http.sslkey", var))
                return git_config_pathname(&ssl_key, var, value);
+       if (!strcmp("http.sslkeytype", var))
+               return git_config_string(&ssl_key_type, var, value);
        if (!strcmp("http.sslcapath", var))
                return git_config_pathname(&ssl_capath, var, value);
        if (!strcmp("http.sslcainfo", var))
@@ -295,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;
        }
 
@@ -345,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)
@@ -416,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)
@@ -618,17 +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)) {
+           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, ']');
@@ -701,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 };
@@ -904,10 +1052,14 @@ static CURL *get_curl_handle(void)
 
        if (ssl_cert)
                curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
+       if (ssl_cert_type)
+               curl_easy_setopt(result, CURLOPT_SSLCERTTYPE, ssl_cert_type);
        if (has_cert_password())
                curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password);
        if (ssl_key)
                curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
+       if (ssl_key_type)
+               curl_easy_setopt(result, CURLOPT_SSLKEYTYPE, ssl_key_type);
        if (ssl_capath)
                curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
 #ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
@@ -1142,7 +1294,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
                curl_ssl_verify = 0;
 
        set_from_env(&ssl_cert, "GIT_SSL_CERT");
+       set_from_env(&ssl_cert_type, "GIT_SSL_CERT_TYPE");
        set_from_env(&ssl_key, "GIT_SSL_KEY");
+       set_from_env(&ssl_key_type, "GIT_SSL_KEY_TYPE");
        set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
        set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
 
@@ -1895,6 +2049,8 @@ static int http_request(const char *url,
                                         fwrite_buffer);
        }
 
+       curl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION, fwrite_wwwauth);
+
        accept_language = http_get_accept_language_header();
 
        if (accept_language)
diff --git a/http.h b/http.h
index 77c042706c6597e347d1b8cc05d3f5972e2de117..3a409bccd4e6197874a97629c36b050ca923b944 100644 (file)
--- a/http.h
+++ b/http.h
@@ -1,7 +1,9 @@
 #ifndef HTTP_H
 #define HTTP_H
 
-#include "cache.h"
+struct packed_git;
+
+#include "git-zlib.h"
 
 #include <curl/curl.h>
 #include <curl/easy.h>
diff --git a/ident.c b/ident.c
index 6de76f9421d57f38c478cca68fcb97c4ede2d36c..cc7afdbf8197e981e02b6257a4618197063db69f 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -5,10 +5,13 @@
  *
  * Copyright (C) 2005 Linus Torvalds
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "ident.h"
 #include "config.h"
 #include "date.h"
+#include "gettext.h"
 #include "mailmap.h"
+#include "strbuf.h"
 
 static struct strbuf git_default_name = STRBUF_INIT;
 static struct strbuf git_default_email = STRBUF_INIT;
@@ -200,7 +203,6 @@ void reset_ident_date(void)
 static int crud(unsigned char c)
 {
        return  c <= 32  ||
-               c == '.' ||
                c == ',' ||
                c == ':' ||
                c == ';' ||
@@ -668,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
new file mode 100644 (file)
index 0000000..6a79feb
--- /dev/null
+++ b/ident.h
@@ -0,0 +1,69 @@
+#ifndef IDENT_H
+#define IDENT_H
+
+#include "string-list.h"
+
+struct ident_split {
+       const char *name_begin;
+       const char *name_end;
+       const char *mail_begin;
+       const char *mail_end;
+       const char *date_begin;
+       const char *date_end;
+       const char *tz_begin;
+       const char *tz_end;
+};
+
+#define IDENT_STRICT          1
+#define IDENT_NO_DATE         2
+#define IDENT_NO_NAME         4
+
+enum want_ident {
+       WANT_BLANK_IDENT,
+       WANT_AUTHOR_IDENT,
+       WANT_COMMITTER_IDENT
+};
+
+const char *ident_default_name(void);
+const char *ident_default_email(void);
+/*
+ * Prepare an ident to fall back on if the user didn't configure it.
+ */
+void prepare_fallback_ident(const char *name, const char *email);
+void reset_ident_date(void);
+/*
+ * Signals an success with 0, but time part of the result may be NULL
+ * if the input lacks timestamp and zone
+ */
+int split_ident_line(struct ident_split *, const char *, int);
+
+/*
+ * Given a commit or tag object buffer and the commit or tag headers, replaces
+ * the idents in the headers with their canonical versions using the mailmap mechanism.
+ */
+void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);
+
+/*
+ * Compare split idents for equality or strict ordering. Note that we
+ * compare only the ident part of the line, ignoring any timestamp.
+ *
+ * Because there are two fields, we must choose one as the primary key; we
+ * currently arbitrarily pick the email.
+ */
+int ident_cmp(const struct ident_split *, const struct ident_split *);
+
+const char *git_author_info(int);
+const char *git_committer_info(int);
+const char *fmt_ident(const char *name, const char *email,
+                     enum want_ident whose_ident,
+                     const char *date_str, int);
+const char *fmt_name(enum want_ident);
+
+int committer_ident_sufficiently_given(void);
+int author_ident_sufficiently_given(void);
+
+struct config_context;
+int git_ident_config(const char *, const char *, const struct config_context *,
+                    void *);
+
+#endif
index a50af56b827033dc68923e038566e7718fb81a65..06386e0b3bd878b163624f49e953686d4d49f8d1 100644 (file)
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "credential.h"
 #include "exec-cmd.h"
+#include "gettext.h"
 #include "run-command.h"
 #include "parse-options.h"
+#include "setup.h"
+#include "strbuf.h"
 #if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
 typedef void *SSL;
 #endif
@@ -133,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 {
@@ -782,7 +783,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");
@@ -824,8 +825,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);
@@ -913,7 +912,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;
@@ -1319,7 +1318,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))
@@ -1337,7 +1337,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'");
@@ -1353,7 +1353,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;
 }
@@ -1411,16 +1411,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);
@@ -1428,25 +1428,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);
 
index f1cfd8fa8c664bfca0dcaada59e59af8dd2db38a..005c820aa42e1f3c98bd2c1a376bd3a52bfc32a2 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "json-writer.h"
 
 void jw_init(struct json_writer *jw)
diff --git a/khash.h b/khash.h
index cb79bf885674ea6fc54fdcea17543739530a3b14..ff8816317785862662b1eeb2fe5036b801be1773 100644 (file)
--- a/khash.h
+++ b/khash.h
@@ -26,8 +26,7 @@
 #ifndef __AC_KHASH_H
 #define __AC_KHASH_H
 
-#include "cache.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 08aadf03117c5069116bb7e7fa4aa5ed7a9b1fb0..bbfcf815a567b053bd0206ddb7bb38d138731bd1 100644 (file)
--- a/kwset.c
+++ b/kwset.c
@@ -32,7 +32,7 @@
    String Matching:  An Aid to Bibliographic Search," CACM June 1975,
    Vol. 18, No. 6, which describes the failure function used below. */
 
-#include "cache.h"
+#include "git-compat-util.h"
 
 #include "kwset.h"
 #include "compat/obstack.h"
@@ -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 d2632690d5107b53ee8a7ac4832cd85eb8c7bfc1..fd8026fe20182e5d90dad6db72ab453b5ed0a23c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "levenshtein.h"
 
 /*
index a7f3e7f6ce43e0ce4786e417608a1a43bac47105..790ab732127d04df57b330f06b43785532fd68b9 100644 (file)
@@ -1,12 +1,13 @@
 #include "git-compat-util.h"
 #include "line-range.h"
-#include "cache.h"
+#include "hex.h"
 #include "tag.h"
 #include "blob.h"
 #include "tree.h"
 #include "diff.h"
 #include "commit.h"
 #include "decorate.h"
+#include "repository.h"
 #include "revision.h"
 #include "xdiff-interface.h"
 #include "strbuf.h"
 #include "graph.h"
 #include "userdiff.h"
 #include "line-log.h"
+#include "setup.h"
 #include "strvec.h"
 #include "bloom.h"
+#include "tree-walk.h"
 
 static void range_set_grow(struct range_set *rs, size_t extra)
 {
@@ -1281,7 +1284,8 @@ int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit
        return changed;
 }
 
-static enum rewrite_result line_log_rewrite_one(struct rev_info *rev, struct commit **pp)
+static enum rewrite_result line_log_rewrite_one(struct rev_info *rev UNUSED,
+                                               struct commit **pp)
 {
        for (;;) {
                struct commit *p = *pp;
index 82ae8d98a403bb644eede373a8def1a37a811fdd..adff361b1bc93905641341df88a7cfcbfb6c118d 100644 (file)
@@ -5,6 +5,7 @@
 
 struct rev_info;
 struct commit;
+struct string_list;
 
 /* A range [start,end].  Lines are numbered starting at 0, and the
  * ranges include start but exclude end. */
index ecffc09be6ec5c1a9646ac152a899f3415f6321d..5416cbcf409d2689d4fe620564f2e010a93131b8 100644 (file)
@@ -3,7 +3,7 @@
  * algorithm for dense and sparse linear assignment problems</i>. Computing,
  * 38(4), 325-340.
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "linear-assignment.h"
 
 #define COST(column, row) cost[(column) + column_count * (row)]
index ee01bcd2cc365c12c72bcd3f5597ecceecb2a7d9..8a08b7af49c1ff7750296508102bf67807027bea 100644 (file)
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "commit.h"
 #include "config.h"
+#include "gettext.h"
 #include "revision.h"
 #include "strvec.h"
 #include "list-objects.h"
@@ -9,6 +10,7 @@
 #include "promisor-remote.h"
 #include "trace.h"
 #include "url.h"
+#include "parse-options.h"
 
 static int parse_combine_filter(
        struct list_objects_filter_options *filter_options,
@@ -341,7 +343,7 @@ void partial_clone_register(
        char *filter_name;
 
        /* Check if it is already registered */
-       if ((promisor_remote = promisor_remote_find(remote))) {
+       if ((promisor_remote = repo_promisor_remote_find(the_repository, remote))) {
                if (promisor_remote->partial_clone_filter)
                        /*
                         * Remote is already registered and a filter is already
@@ -369,14 +371,15 @@ void partial_clone_register(
        free(filter_name);
 
        /* Make sure the config info are reset */
-       promisor_remote_reinit();
+       repo_promisor_remote_reinit(the_repository);
 }
 
 void partial_clone_get_default_filter_spec(
        struct list_objects_filter_options *filter_options,
        const char *remote)
 {
-       struct promisor_remote *promisor = promisor_remote_find(remote);
+       struct promisor_remote *promisor = repo_promisor_remote_find(the_repository,
+                                                                    remote);
        struct strbuf errbuf = STRBUF_INIT;
 
        /*
index 1fe393f447303a6d94abbd571a1ea83a1bfc7620..55fab8563d20a5a7ada0e9fd1215303808c5853d 100644 (file)
@@ -1,9 +1,11 @@
 #ifndef LIST_OBJECTS_FILTER_OPTIONS_H
 #define LIST_OBJECTS_FILTER_OPTIONS_H
 
-#include "cache.h"
-#include "parse-options.h"
-#include "string-list.h"
+#include "gettext.h"
+#include "object.h"
+#include "strbuf.h"
+
+struct option;
 
 /*
  * The list of defined filters for list-objects.
index 7ed21cb299c126fb2d2107eb3e418a18e64fbc6c..9327ccd5057cb6fffc9fcd9a92f2939a50b50253 100644 (file)
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "dir.h"
+#include "gettext.h"
+#include "hex.h"
 #include "tag.h"
 #include "commit.h"
 #include "tree.h"
@@ -12,7 +14,8 @@
 #include "list-objects-filter-options.h"
 #include "oidmap.h"
 #include "oidset.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 
 /* Remember to update object flag allocation in object.h */
 /*
index 7528fe1db2c85c0b4d923854ef3ec53c3a8f1fad..e60a6cd5b46ef8ded2dfbbe86d75cd8d107f548d 100644 (file)
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "tag.h"
 #include "commit.h"
+#include "gettext.h"
+#include "hex.h"
 #include "tree.h"
 #include "blob.h"
 #include "diff.h"
@@ -10,7 +12,7 @@
 #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"
 
 struct traversal_context {
@@ -64,7 +66,7 @@ static void process_blob(struct traversal_context *ctx,
         * of missing objects.
         */
        if (ctx->revs->exclude_promisor_objects &&
-           !has_object_file(&obj->oid) &&
+           !repo_has_object_file(the_repository, &obj->oid) &&
            is_promisor_object(&obj->oid))
                return;
 
@@ -100,7 +102,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;
@@ -227,7 +229,8 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
                struct commit *parent = parents->item;
                if (!(parent->object.flags & UNINTERESTING))
                        continue;
-               mark_tree_uninteresting(revs->repo, get_commit_tree(parent));
+               mark_tree_uninteresting(revs->repo,
+                                       repo_get_commit_tree(the_repository, parent));
                if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
                        parent->object.flags |= SHOWN;
                        show_edge(parent);
@@ -244,7 +247,8 @@ static void add_edge_parents(struct commit *commit,
 
        for (parents = commit->parents; parents; parents = parents->next) {
                struct commit *parent = parents->item;
-               struct tree *tree = get_commit_tree(parent);
+               struct tree *tree = repo_get_commit_tree(the_repository,
+                                                        parent);
 
                if (!tree)
                        continue;
@@ -275,7 +279,8 @@ void mark_edges_uninteresting(struct rev_info *revs,
 
                for (list = revs->commits; list; list = list->next) {
                        struct commit *commit = list->item;
-                       struct tree *tree = get_commit_tree(commit);
+                       struct tree *tree = repo_get_commit_tree(the_repository,
+                                                                commit);
 
                        if (commit->object.flags & UNINTERESTING)
                                tree->object.flags |= UNINTERESTING;
@@ -291,7 +296,7 @@ void mark_edges_uninteresting(struct rev_info *revs,
                        struct commit *commit = list->item;
                        if (commit->object.flags & UNINTERESTING) {
                                mark_tree_uninteresting(revs->repo,
-                                                       get_commit_tree(commit));
+                                                       repo_get_commit_tree(the_repository, commit));
                                if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
                                        commit->object.flags |= SHOWN;
                                        show_edge(commit);
@@ -309,7 +314,7 @@ void mark_edges_uninteresting(struct rev_info *revs,
                        if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
                                continue;
                        mark_tree_uninteresting(revs->repo,
-                                               get_commit_tree(commit));
+                                               repo_get_commit_tree(the_repository, commit));
                        if (!(obj->flags & SHOWN)) {
                                obj->flags |= SHOWN;
                                show_edge(commit);
@@ -376,8 +381,9 @@ static void do_traverse(struct traversal_context *ctx)
                 */
                if (!ctx->revs->tree_objects)
                        ; /* do not bother loading tree */
-               else if (get_commit_tree(commit)) {
-                       struct tree *tree = get_commit_tree(commit);
+               else if (repo_get_commit_tree(the_repository, commit)) {
+                       struct tree *tree = repo_get_commit_tree(the_repository,
+                                                                commit);
                        tree->object.flags |= NOT_USER_GIVEN;
                        add_pending_tree(ctx->revs, tree);
                } else if (commit->object.parsed) {
index cc9a4b84283be34cdcd72770d77e2ef1adb998a6..1d5ed0168287464e24d60e30b0cfbce181676535 100644 (file)
@@ -2,7 +2,9 @@
  * Copyright (c) 2005, Junio C Hamano
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "gettext.h"
 #include "lockfile.h"
 
 /*
index 1dd5fcbf7be433740d83382db4c401d438a51720..208c69cbb79021ad471467292572c5587b103a6d 100644 (file)
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "commit-reach.h"
 #include "config.h"
 #include "diff.h"
-#include "object-store.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "tmp-objdir.h"
 #include "commit.h"
@@ -12,6 +15,8 @@
 #include "merge-ort.h"
 #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"
@@ -20,6 +25,9 @@
 #include "help.h"
 #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" };
 static int decoration_loaded;
@@ -150,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)) {
@@ -196,7 +204,8 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
        return 0;
 }
 
-static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
+static int add_graft_decoration(const struct commit_graft *graft,
+                               void *cb_data UNUSED)
 {
        struct commit *commit = lookup_commit(the_repository, &graft->oid);
        if (!commit)
@@ -233,7 +242,8 @@ static void show_parents(struct commit *commit, int abbrev, FILE *file)
        struct commit_list *p;
        for (p = commit->parents; p ; p = p->next) {
                struct commit *parent = p->item;
-               fprintf(file, " %s", find_unique_abbrev(&parent->object.oid, abbrev));
+               fprintf(file, " %s",
+                       repo_find_unique_abbrev(the_repository, &parent->object.oid, abbrev));
        }
 }
 
@@ -241,7 +251,8 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 {
        struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
        for ( ; p; p = p->next) {
-               fprintf(opt->diffopt.file, " %s", find_unique_abbrev(&p->item->object.oid, abbrev));
+               fprintf(opt->diffopt.file, " %s",
+                       repo_find_unique_abbrev(the_repository, &p->item->object.oid, abbrev));
        }
 }
 
@@ -405,7 +416,8 @@ void fmt_output_commit(struct strbuf *filename,
        struct pretty_print_context ctx = {0};
        struct strbuf subject = STRBUF_INIT;
 
-       format_commit_message(commit, "%f", &subject, &ctx);
+       repo_format_commit_message(the_repository, commit, "%f", &subject,
+                                  &ctx);
        fmt_output_subject(filename, subject.buf, info);
        strbuf_release(&subject);
 }
@@ -440,7 +452,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
        fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
        graph_show_oneline(opt->graph);
        if (opt->message_id) {
-               fprintf(opt->diffopt.file, "Message-Id: <%s>\n", opt->message_id);
+               fprintf(opt->diffopt.file, "Message-ID: <%s>\n", opt->message_id);
                graph_show_oneline(opt->graph);
        }
        if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
@@ -644,7 +656,8 @@ void show_log(struct rev_info *opt)
 
                if (!opt->graph)
                        put_revision_mark(opt, commit);
-               fputs(find_unique_abbrev(&commit->object.oid, abbrev_commit), opt->diffopt.file);
+               fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev_commit),
+                     opt->diffopt.file);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit, opt->diffopt.file);
                if (opt->children.name)
@@ -706,8 +719,8 @@ void show_log(struct rev_info *opt)
 
                if (!opt->graph)
                        put_revision_mark(opt, commit);
-               fputs(find_unique_abbrev(&commit->object.oid,
-                                        abbrev_commit),
+               fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid,
+                                             abbrev_commit),
                      opt->diffopt.file);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit, opt->diffopt.file);
@@ -715,7 +728,7 @@ void show_log(struct rev_info *opt)
                        show_children(opt, commit, abbrev_commit);
                if (parent)
                        fprintf(opt->diffopt.file, " (from %s)",
-                              find_unique_abbrev(&parent->object.oid, abbrev_commit));
+                              repo_find_unique_abbrev(the_repository, &parent->object.oid, abbrev_commit));
                fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file);
                show_decorations(opt, commit);
                if (opt->commit_format == CMIT_FMT_ONELINE) {
@@ -846,7 +859,7 @@ void show_log(struct rev_info *opt)
                 * Pass minimum required diff-options to range-diff; others
                 * can be added later if deemed desirable.
                 */
-               diff_setup(&opts);
+               repo_diff_setup(the_repository, &opts);
                opts.file = opt->diffopt.file;
                opts.use_color = opt->diffopt.use_color;
                diff_setup_done(&opts);
@@ -982,15 +995,17 @@ static int do_remerge_diff(struct rev_info *opt,
        o.msg_header_prefix = "remerge";
 
        ctx.abbrev = DEFAULT_ABBREV;
-       format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx);
-       format_commit_message(parent2, "%h (%s)", &parent2_desc, &ctx);
+       repo_format_commit_message(the_repository, parent1, "%h (%s)",
+                                  &parent1_desc, &ctx);
+       repo_format_commit_message(the_repository, parent2, "%h (%s)",
+                                  &parent2_desc, &ctx);
        o.branch1 = parent1_desc.buf;
        o.branch2 = parent2_desc.buf;
 
        /* Parse the relevant commits and get the merge bases */
        parse_commit_or_die(parent1);
        parse_commit_or_die(parent2);
-       bases = get_merge_bases(parent1, parent2);
+       bases = repo_get_merge_bases(the_repository, parent1, parent2);
 
        /* Re-merge the parents */
        merge_incore_recursive(&o, bases, parent1, parent2, &res);
index e7e4641cf83c5b7cfd4457b54a88115723ac979d..bdb64328154e519ceaa4138045ee4124c0fb3381 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;
index 697d4beb8de43a4a7ae48be8284e10c6be2a9bfd..0e49b932c308b24a5654910d5e0197cf1388162e 100644 (file)
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -1,4 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "repository.h"
 #include "refs.h"
 #include "remote.h"
 #include "config.h"
 #include "string-list.h"
 
-static int config_read;
-static int advertise_unborn;
-static int allow_unborn;
-
-static void ensure_config_read(void)
+static enum {
+       UNBORN_IGNORE = 0,
+       UNBORN_ALLOW,
+       UNBORN_ADVERTISE /* implies ALLOW */
+} unborn_config(struct repository *r)
 {
        const char *str = NULL;
 
-       if (config_read)
-               return;
-
-       if (repo_config_get_string_tmp(the_repository, "lsrefs.unborn", &str)) {
+       if (repo_config_get_string_tmp(r, "lsrefs.unborn", &str)) {
                /*
                 * If there is no such config, advertise and allow it by
                 * default.
                 */
-               advertise_unborn = 1;
-               allow_unborn = 1;
+               return UNBORN_ADVERTISE;
        } else {
                if (!strcmp(str, "advertise")) {
-                       advertise_unborn = 1;
-                       allow_unborn = 1;
+                       return UNBORN_ADVERTISE;
                } else if (!strcmp(str, "allow")) {
-                       allow_unborn = 1;
+                       return UNBORN_ALLOW;
                } else if (!strcmp(str, "ignore")) {
-                       /* do nothing */
+                       return UNBORN_IGNORE;
                } else {
                        die(_("invalid value for '%s': '%s'"),
                            "lsrefs.unborn", str);
                }
        }
-       config_read = 1;
 }
 
 /*
@@ -74,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;
 };
 
@@ -139,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;
@@ -157,9 +156,8 @@ 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);
 
-       ensure_config_read();
        git_config(ls_refs_config, &data);
 
        while (packet_reader_read(request) == PACKET_READ_NORMAL) {
@@ -175,7 +173,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
                                strvec_push(&data.prefixes, out);
                }
                else if (!strcmp("unborn", arg))
-                       data.unborn = allow_unborn;
+                       data.unborn = !!unborn_config(r);
                else
                        die(_("unexpected line: '%s'"), arg);
        }
@@ -196,21 +194,19 @@ 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;
 }
 
 int ls_refs_advertise(struct repository *r, struct strbuf *value)
 {
-       if (value) {
-               ensure_config_read();
-               if (advertise_unborn)
-                       strbuf_addstr(value, "unborn");
-       }
+       if (value && unborn_config(r) == UNBORN_ADVERTISE)
+               strbuf_addstr(value, "unborn");
 
        return 1;
 }
index 833d28612f77473e9a50d6329ba55bd9706ba81d..931505363cde08b0475f200e9c60fd3c034413b7 100644 (file)
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "gettext.h"
+#include "hex.h"
 #include "utf8.h"
 #include "strbuf.h"
 #include "mailinfo.h"
@@ -597,7 +599,7 @@ static int check_header(struct mailinfo *mi,
                ret = 1;
                goto check_header_out;
        }
-       if (parse_header(line, "Message-Id", mi, &sb)) {
+       if (parse_header(line, "Message-ID", mi, &sb)) {
                if (mi->add_message_id)
                        mi->message_id = strbuf_detach(&sb, NULL);
                ret = 1;
@@ -829,7 +831,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
        if (patchbreak(line)) {
                if (mi->message_id)
                        strbuf_addf(&mi->log_message,
-                                   "Message-Id: %s\n", mi->message_id);
+                                   "Message-ID: %s\n", mi->message_id);
                return 1;
        }
 
@@ -1239,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 da2589b08229813963347115a001d8ce6f45ae32..3d6a5e9400f4c8195d0f58ab58f3f9a4dfa0acba 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,17 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
 #include "string-list.h"
 #include "mailmap.h"
-#include "object-store.h"
-
-#define DEBUG_MAILMAP 0
-#if DEBUG_MAILMAP
-#define debug_mm(...) fprintf(stderr, __VA_ARGS__)
-#define debug_str(X) ((X) ? (X) : "(none)")
-#else
-__attribute__((format (printf, 1, 2)))
-static inline void debug_mm(const char *format, ...) {}
-static inline const char *debug_str(const char *s) { return s; }
-#endif
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "setup.h"
 
 const char *git_mailmap_file;
 const char *git_mailmap_blob;
@@ -30,23 +23,17 @@ struct mailmap_entry {
        struct string_list namemap;
 };
 
-static void free_mailmap_info(void *p, const char *s)
+static void free_mailmap_info(void *p, const char *s UNUSED)
 {
        struct mailmap_info *mi = (struct mailmap_info *)p;
-       debug_mm("mailmap: -- complex: '%s' -> '%s' <%s>\n",
-                s, debug_str(mi->name), debug_str(mi->email));
        free(mi->name);
        free(mi->email);
        free(mi);
 }
 
-static void free_mailmap_entry(void *p, const char *s)
+static void free_mailmap_entry(void *p, const char *s UNUSED)
 {
        struct mailmap_entry *me = (struct mailmap_entry *)p;
-       debug_mm("mailmap: removing entries for <%s>, with %"PRIuMAX" sub-entries\n",
-                s, (uintmax_t)me->namemap.nr);
-       debug_mm("mailmap: - simple: '%s' <%s>\n",
-                debug_str(me->name), debug_str(me->email));
 
        free(me->name);
        free(me->email);
@@ -93,8 +80,6 @@ static void add_mapping(struct string_list *map,
        }
 
        if (!old_name) {
-               debug_mm("mailmap: adding (simple) entry for '%s'\n", old_email);
-
                /* Replace current name and new email for simple entry */
                if (new_name) {
                        free(me->name);
@@ -106,15 +91,10 @@ static void add_mapping(struct string_list *map,
                }
        } else {
                struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
-               debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
                mi->name = xstrdup_or_null(new_name);
                mi->email = xstrdup_or_null(new_email);
                string_list_insert(&me->namemap, old_name)->util = mi;
        }
-
-       debug_mm("mailmap:  '%s' <%s> -> '%s' <%s>\n",
-                debug_str(old_name), old_email,
-                debug_str(new_name), debug_str(new_email));
 }
 
 static char *parse_name_and_email(char *buffer, char **name,
@@ -213,10 +193,10 @@ static int read_mailmap_blob(struct string_list *map, const char *name)
 
        if (!name)
                return 0;
-       if (get_oid(name, &oid) < 0)
+       if (repo_get_oid(the_repository, name, &oid) < 0)
                return 0;
 
-       buf = read_object_file(&oid, &type, &size);
+       buf = repo_read_object_file(the_repository, &oid, &type, &size);
        if (!buf)
                return error("unable to read mailmap object at %s", name);
        if (type != OBJ_BLOB)
@@ -250,11 +230,8 @@ int read_mailmap(struct string_list *map)
 
 void clear_mailmap(struct string_list *map)
 {
-       debug_mm("mailmap: clearing %"PRIuMAX" entries...\n",
-                (uintmax_t)map->nr);
        map->strdup_strings = 1;
        string_list_clear_func(map, free_mailmap_entry);
-       debug_mm("mailmap: cleared\n");
 }
 
 /*
@@ -315,10 +292,6 @@ int map_user(struct string_list *map,
        struct string_list_item *item;
        struct mailmap_entry *me;
 
-       debug_mm("map_user: map '%.*s' <%.*s>\n",
-                (int)*namelen, debug_str(*name),
-                (int)*emaillen, debug_str(*email));
-
        item = lookup_prefix(map, *email, *emaillen);
        if (item) {
                me = (struct mailmap_entry *)item->util;
@@ -336,10 +309,8 @@ int map_user(struct string_list *map,
        }
        if (item) {
                struct mailmap_info *mi = (struct mailmap_info *)item->util;
-               if (mi->name == NULL && mi->email == NULL) {
-                       debug_mm("map_user:  -- (no simple mapping)\n");
+               if (mi->name == NULL && mi->email == NULL)
                        return 0;
-               }
                if (mi->email) {
                                *email = mi->email;
                                *emaillen = strlen(*email);
@@ -348,11 +319,7 @@ int map_user(struct string_list *map,
                                *name = mi->name;
                                *namelen = strlen(*name);
                }
-               debug_mm("map_user:  to '%.*s' <%.*s>\n",
-                        (int)*namelen, debug_str(*name),
-                        (int)*emaillen, debug_str(*email));
                return 1;
        }
-       debug_mm("map_user:  --\n");
        return 0;
 }
index 7e99fccb46c92e012fa32fafb6ed27c217fdcc4d..0f8fd2c586feaccd4bb4df772b8e8393148ccf6c 100644 (file)
--- a/mailmap.h
+++ b/mailmap.h
@@ -3,6 +3,9 @@
 
 struct string_list;
 
+extern const char *git_mailmap_file;
+extern const char *git_mailmap_blob;
+
 int read_mailmap(struct string_list *map);
 void clear_mailmap(struct string_list *map);
 
index 49398e599fe3afdc88f481608fb58b0887b019e3..0885ac681cd5055f80fb5088b04c92eed8e7f291 100644 (file)
@@ -1,7 +1,10 @@
-#include "cache.h"
+#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)
 {
@@ -55,7 +58,7 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
        enum object_type type;
        unsigned long size;
 
-       buffer = read_object_file(hash, &type, &size);
+       buffer = repo_read_object_file(the_repository, hash, &type, &size);
        if (!buffer)
                die("unable to read tree (%s)", oid_to_hex(hash));
        if (type != OBJ_TREE)
@@ -188,7 +191,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
        if (*subpath)
                subpath++;
 
-       buf = read_object_file(oid1, &type, &sz);
+       buf = repo_read_object_file(the_repository, oid1, &type, &sz);
        if (!buf)
                die("cannot read tree %s", oid_to_hex(oid1));
        init_tree_desc(&desc, buf, sz);
diff --git a/match-trees.h b/match-trees.h
new file mode 100644 (file)
index 0000000..e3877ac
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef MATCH_TREES_H
+#define MATCH_TREES_H
+
+struct object_id;
+struct repository;
+
+void shift_tree(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, int);
+void shift_tree_by(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, const char *);
+
+#endif /* MATCH_TREES_H */
index 599d8e895f81216e0e0cb44696734cb2a157309b..c34846d176c886ecb9f028ec48bb847402d242f9 100644 (file)
@@ -2,7 +2,7 @@
  * Memory Pool implementation logic.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "mem-pool.h"
 
 #define BLOCK_GROWTH_SIZE (1024 * 1024 - sizeof(struct mp_block))
index 8138090f81cf726ee9834daa7edbfc5b542aec44..9293cbf75c8ab737a2cf7267d3e31ffd93a48dc8 100644 (file)
@@ -1,10 +1,10 @@
-#include "cache.h"
+#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)
 {
@@ -12,7 +12,8 @@ static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
        unsigned long size;
        enum object_type type;
 
-       buf = read_object_file(&obj->object.oid, &type, &size);
+       buf = repo_read_object_file(the_repository, &obj->object.oid, &type,
+                                   &size);
        if (!buf)
                return -1;
        if (type != OBJ_BLOB) {
@@ -78,7 +79,8 @@ void *merge_blobs(struct index_state *istate, const char *path,
                        return NULL;
                if (!our)
                        our = their;
-               return read_object_file(&our->object.oid, &type, size);
+               return repo_read_object_file(the_repository, &our->object.oid,
+                                            &type, size);
        }
 
        if (fill_mmfile_blob(&f1, our) < 0)
similarity index 91%
rename from ll-merge.c
rename to merge-ll.c
index 130d26501c69cd47b762f13b46ff4835cfa6261a..8fcf2d3710ed1a87bd851abe04dd22a32fafdf84 100644 (file)
@@ -4,13 +4,15 @@
  * Copyright (c) 2007 Junio C Hamano
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "convert.h"
 #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"
 
 struct ll_merge_driver;
 
@@ -189,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);
 
@@ -215,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);
@@ -239,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;
 }
 
@@ -251,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;
@@ -391,7 +404,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
                normalize_file(theirs, path, istate);
        }
 
-       git_check_attr(istate, NULL, path, check);
+       git_check_attr(istate, path, check);
        ll_driver_name = check->items[0].value;
        if (check->items[1].value) {
                marker_size = atoi(check->items[1].value);
@@ -419,7 +432,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
 
        if (!check)
                check = attr_check_initl("conflict-marker-size", NULL);
-       git_check_attr(istate, NULL, path, check);
+       git_check_attr(istate, path, check);
        if (check->items[0].value) {
                marker_size = atoi(check->items[0].value);
                if (marker_size <= 0)
similarity index 100%
rename from ll-merge.h
rename to merge-ll.h
index 748924a69ba3262088c444c0145bc407750daa0a..4acedf3c3386d7c9c2e57eebabddb1fe9ec27331 100644 (file)
@@ -1,6 +1,10 @@
-#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 d1611ca400a40b05914a14759a009bf16d76f5ce..8631c997002dbbdb1282619c77cc3ac8fd96f880 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 "diff.h"
 #include "diffcore.h"
 #include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "entry.h"
-#include "ll-merge.h"
-#include "object-store.h"
+#include "merge-ll.h"
+#include "match-trees.h"
+#include "mem-pool.h"
+#include "object-name.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"
+#include "trace2.h"
 #include "tree.h"
 #include "unpack-trees.h"
 #include "xdiff-interface.h"
@@ -3505,7 +3516,7 @@ static int read_oid_strbuf(struct merge_options *opt,
        void *buf;
        enum object_type type;
        unsigned long size;
-       buf = read_object_file(oid, &type, &size);
+       buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (!buf)
                return err(opt, _("cannot read object %s"), oid_to_hex(oid));
        if (type != OBJ_BLOB) {
@@ -4216,7 +4227,7 @@ static void prefetch_for_content_merges(struct merge_options *opt,
        struct string_list_item *e;
        struct oid_array to_fetch = OID_ARRAY_INIT;
 
-       if (opt->repo != the_repository || !has_promisor_remote())
+       if (opt->repo != the_repository || !repo_has_promisor_remote(the_repository))
                return;
 
        for (e = &plist->items[plist->nr-1]; e >= plist->items; --e) {
@@ -4715,14 +4726,14 @@ void merge_switch_to_result(struct merge_options *opt,
 void merge_finalize(struct merge_options *opt,
                    struct merge_result *result)
 {
-       struct merge_options_internal *opti = result->priv;
-
        if (opt->renormalize)
                git_attr_set_direction(GIT_ATTR_CHECKIN);
        assert(opt->priv == NULL);
 
-       clear_or_reinit_internal_opts(opti, 0);
-       FREE_AND_NULL(opti);
+       if (result->priv) {
+               clear_or_reinit_internal_opts(result->priv, 0);
+               FREE_AND_NULL(result->priv);
+       }
 }
 
 /*** Function Grouping: helper functions for merge_incore_*() ***/
@@ -5017,7 +5028,7 @@ static void merge_ort_internal(struct merge_options *opt,
        struct strbuf merge_base_abbrev = STRBUF_INIT;
 
        if (!merge_bases) {
-               merge_bases = get_merge_bases(h1, h2);
+               merge_bases = repo_get_merge_bases(the_repository, h1, h2);
                /* See merge-ort.h:merge_incore_recursive() declaration NOTE */
                merge_bases = reverse_commit_list(merge_bases);
        }
index a994c9a5fcdb040b3ecb80db0489a50c1394ac75..ce56ec1a7802c5eac51d404e03220b83e52ebe1c 100644 (file)
@@ -2,7 +2,7 @@
 #define MERGE_ORT_H
 
 #include "merge-recursive.h"
-#include "hash.h"
+#include "hash-ll.h"
 
 struct commit;
 struct tree;
index ae469f8cc81d58a2be40be4e0365c715866012ec..6a4081bb0f522bf556610fa0e11239b5c7fcddb9 100644 (file)
@@ -3,14 +3,13 @@
  * 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 "alloc.h"
 #include "attr.h"
 #include "blob.h"
-#include "builtin.h"
 #include "cache-tree.h"
 #include "commit.h"
 #include "commit-reach.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "dir.h"
-#include "ll-merge.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "merge-ll.h"
 #include "lockfile.h"
-#include "object-store.h"
+#include "match-trees.h"
+#include "name-hash.h"
+#include "object-file.h"
+#include "object-name.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"
+#include "symlinks.h"
 #include "tag.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
@@ -951,7 +960,8 @@ static int update_file_flags(struct merge_options *opt,
                        goto update_index;
                }
 
-               buf = read_object_file(&contents->oid, &type, &size);
+               buf = repo_read_object_file(the_repository, &contents->oid,
+                                           &type, &size);
                if (!buf) {
                        ret = err(opt, _("cannot read object %s '%s'"),
                                  oid_to_hex(&contents->oid), path);
@@ -3021,7 +3031,7 @@ static int read_oid_strbuf(struct merge_options *opt,
        void *buf;
        enum object_type type;
        unsigned long size;
-       buf = read_object_file(oid, &type, &size);
+       buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (!buf)
                return err(opt, _("cannot read object %s"), oid_to_hex(oid));
        if (type != OBJ_BLOB) {
@@ -3592,7 +3602,7 @@ static int merge_recursive_internal(struct merge_options *opt,
        }
 
        if (!merge_bases) {
-               merge_bases = get_merge_bases(h1, h2);
+               merge_bases = repo_get_merge_bases(the_repository, h1, h2);
                merge_bases = reverse_commit_list(merge_bases);
        }
 
@@ -3797,7 +3807,7 @@ static struct commit *get_ref(struct repository *repo,
                return make_virtual_commit(repo, (struct tree*)object, name);
        if (object->type != OBJ_COMMIT)
                return NULL;
-       if (parse_commit((struct commit *)object))
+       if (repo_parse_commit(repo, (struct commit *)object))
                return NULL;
        return (struct commit *)object;
 }
diff --git a/merge.c b/merge.c
index 445b4f19aa8618b5641f3f007e8cb42d9d39b57c..b60925459c292bbb4a9daae46534edfbb3eca756 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -1,10 +1,16 @@
-#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"
 #include "tree-walk.h"
 #include "unpack-trees.h"
 #include "dir.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 7cfad04a24027c1f0703dafdeeb31989414a13c5..931f55735037fcc4de53005ef0970e9ed3781885 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -1,10 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
 #include "csum-file.h"
 #include "dir.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "hash-lookup.h"
 #include "midx.h"
 #include "progress.h"
@@ -249,7 +253,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;
 }
 
@@ -266,7 +270,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;
-               return get_be64(m->chunk_large_offsets + sizeof(uint64_t) * offset32);
+               return get_be64(m->chunk_large_offsets +
+                               st_mult(sizeof(uint64_t), offset32));
        }
 
        return offset32;
@@ -440,14 +445,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;
@@ -579,12 +584,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);
 }
 
@@ -663,17 +670,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
@@ -716,7 +724,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));
@@ -1326,17 +1335,17 @@ static int write_midx_internal(const char *object_dir,
        }
 
        if (preferred_pack_name) {
-               int found = 0;
+               ctx.preferred_pack_idx = -1;
+
                for (i = 0; i < ctx.nr; i++) {
                        if (!cmp_idx_or_pack_name(preferred_pack_name,
                                                  ctx.info[i].pack_name)) {
                                ctx.preferred_pack_idx = i;
-                               found = 1;
                                break;
                        }
                }
 
-               if (!found)
+               if (ctx.preferred_pack_idx == -1)
                        warning(_("unknown preferred pack: '%s'"),
                                preferred_pack_name);
        } else if (ctx.nr &&
@@ -1491,21 +1500,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);
        }
 
@@ -1607,7 +1617,7 @@ struct clear_midx_data {
        const char *ext;
 };
 
-static void clear_midx_file_ext(const char *full_path, size_t full_path_len,
+static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUSED,
                                const char *file_name, void *_data)
 {
        struct clear_midx_data *data = _data;
@@ -1983,8 +1993,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)
index cd009c7c8ae455324bc9e48aa0f1f4df24211b66..251f036eef6983a66ac13013e5bee3ef770e8f9f 100644 (file)
@@ -5,8 +5,14 @@
  *
  * 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"
 #include "sparse-index.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 b7e79feaf042290c041fbcec439fc2aa8e84a3df..9a5b69632728d1d6877556a330e666ba530a894a 100644 (file)
@@ -1,9 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "default.h"
 #include "../commit.h"
 #include "../fetch-negotiator.h"
 #include "../prio-queue.h"
 #include "../refs.h"
+#include "../repository.h"
 #include "../tag.h"
 
 /* Remember to update object flag allocation in object.h */
@@ -25,7 +26,7 @@ static void rev_list_push(struct negotiation_state *ns,
        if (!(commit->object.flags & mark)) {
                commit->object.flags |= mark;
 
-               if (parse_commit(commit))
+               if (repo_parse_commit(the_repository, commit))
                        return;
 
                prio_queue_put(&ns->rev_list, commit);
@@ -55,30 +56,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
 static void mark_common(struct negotiation_state *ns, struct commit *commit,
                int ancestors_only, int dont_parse)
 {
-       if (commit != NULL && !(commit->object.flags & COMMON)) {
-               struct object *o = (struct object *)commit;
+       struct prio_queue queue = { NULL };
+
+       if (!commit || (commit->object.flags & COMMON))
+               return;
+
+       prio_queue_put(&queue, commit);
+       if (!ancestors_only) {
+               commit->object.flags |= COMMON;
 
-               if (!ancestors_only)
-                       o->flags |= COMMON;
+               if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
+                       ns->non_common_revs--;
+       }
+       while ((commit = prio_queue_get(&queue))) {
+               struct object *o = (struct object *)commit;
 
                if (!(o->flags & SEEN))
                        rev_list_push(ns, commit, SEEN);
                else {
                        struct commit_list *parents;
 
-                       if (!ancestors_only && !(o->flags & POPPED))
-                               ns->non_common_revs--;
                        if (!o->parsed && !dont_parse)
-                               if (parse_commit(commit))
-                                       return;
+                               if (repo_parse_commit(the_repository, commit))
+                                       continue;
 
                        for (parents = commit->parents;
                                        parents;
-                                       parents = parents->next)
-                               mark_common(ns, parents->item, 0,
-                                           dont_parse);
+                                       parents = parents->next) {
+                               struct commit *p = parents->item;
+
+                               if (p->object.flags & COMMON)
+                                       continue;
+
+                               p->object.flags |= COMMON;
+
+                               if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
+                                       ns->non_common_revs--;
+
+                               prio_queue_put(&queue, parents->item);
+                       }
                }
        }
+
+       clear_prio_queue(&queue);
 }
 
 /*
@@ -96,7 +116,7 @@ static const struct object_id *get_rev(struct negotiation_state *ns)
                        return NULL;
 
                commit = prio_queue_get(&ns->rev_list);
-               parse_commit(commit);
+               repo_parse_commit(the_repository, commit);
                parents = commit->parents;
 
                commit->object.flags |= POPPED;
index 60569b83501a0d789452a934fcabcfc7aa5b24e4..7b729376867afee47c76aaf74901aa19f3615804 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "noop.h"
 #include "../commit.h"
 #include "../fetch-negotiator.h"
index 0f5ac48e87608ee9fee69efb94b51d985b60c707..5b91520430c1703762e8712e632850420cba7be8 100644 (file)
@@ -1,9 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "skipping.h"
 #include "../commit.h"
 #include "../fetch-negotiator.h"
+#include "../hex.h"
 #include "../prio-queue.h"
 #include "../refs.h"
+#include "../repository.h"
 #include "../tag.h"
 
 /* Remember to update object flag allocation in object.h */
@@ -50,7 +52,7 @@ struct data {
        int non_common_revs;
 };
 
-static int compare(const void *a_, const void *b_, void *unused)
+static int compare(const void *a_, const void *b_, void *data UNUSED)
 {
        const struct entry *a = a_;
        const struct entry *b = b_;
@@ -84,29 +86,37 @@ static int clear_marks(const char *refname, const struct object_id *oid,
 }
 
 /*
- * Mark this SEEN commit and all its SEEN ancestors as COMMON.
+ * Mark this SEEN commit and all its parsed SEEN ancestors as COMMON.
  */
 static void mark_common(struct data *data, struct commit *seen_commit)
 {
        struct prio_queue queue = { NULL };
        struct commit *c;
 
+       if (seen_commit->object.flags & COMMON)
+               return;
+
        prio_queue_put(&queue, seen_commit);
+       seen_commit->object.flags |= COMMON;
        while ((c = prio_queue_get(&queue))) {
                struct commit_list *p;
-               if (c->object.flags & COMMON)
-                       return;
-               c->object.flags |= COMMON;
+
                if (!(c->object.flags & POPPED))
                        data->non_common_revs--;
 
                if (!c->object.parsed)
-                       return;
+                       continue;
                for (p = c->parents; p; p = p->next) {
-                       if (p->item->object.flags & SEEN)
-                               prio_queue_put(&queue, p->item);
+                       if (!(p->item->object.flags & SEEN) ||
+                           (p->item->object.flags & COMMON))
+                               continue;
+
+                       p->item->object.flags |= COMMON;
+                       prio_queue_put(&queue, p->item);
                }
        }
+
+       clear_prio_queue(&queue);
 }
 
 /*
@@ -183,7 +193,7 @@ static const struct object_id *get_rev(struct data *data)
                if (!(commit->object.flags & COMMON) && !entry->ttl)
                        to_send = commit;
 
-               parse_commit(commit);
+               repo_parse_commit(the_repository, commit);
                for (p = commit->parents; p; p = p->next)
                        parent_pushed |= push_parent(data, entry, p->item);
 
index 9dfd251a8151d4205297b5c27064a01acf448f69..0e1d5b1ac7a48d9bda8f76091a55be7c527e68cc 100644 (file)
@@ -1,9 +1,11 @@
-#include "cache.h"
+#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,
@@ -23,7 +25,8 @@ static int notes_cache_match_validity(struct repository *r,
                return 0;
 
        memset(&pretty_ctx, 0, sizeof(pretty_ctx));
-       format_commit_message(commit, "%s", &msg, &pretty_ctx);
+       repo_format_commit_message(r, commit, "%s", &msg,
+                                  &pretty_ctx);
        strbuf_trim(&msg);
 
        ret = !strcmp(msg.buf, validity);
@@ -81,7 +84,7 @@ char *notes_cache_get(struct notes_cache *c, struct object_id *key_oid,
        value_oid = get_note(&c->tree, key_oid);
        if (!value_oid)
                return NULL;
-       value = read_object_file(value_oid, &type, &size);
+       value = repo_read_object_file(the_repository, value_oid, &type, &size);
 
        *outsize = size;
        return value;
index b4cc594a790965aca297fe87392a50b643e6fb41..8799b522a55f31869dcc8cbfd7229cc8db65af4c 100644 (file)
@@ -1,16 +1,23 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "commit.h"
+#include "gettext.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.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"
 #include "strbuf.h"
+#include "trace.h"
 #include "notes-utils.h"
 #include "commit-reach.h"
 
@@ -326,7 +333,7 @@ static void write_note_to_worktree(const struct object_id *obj,
 {
        enum object_type type;
        unsigned long size;
-       void *buf = read_object_file(note, &type, &size);
+       void *buf = repo_read_object_file(the_repository, note, &type, &size);
 
        if (!buf)
                die("cannot read note %s for object %s",
@@ -566,7 +573,7 @@ int notes_merge(struct notes_merge_options *o,
        trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid));
 
        /* Dereference o->remote_ref into remote_oid */
-       if (get_oid(o->remote_ref, &remote_oid)) {
+       if (repo_get_oid(the_repository, o->remote_ref, &remote_oid)) {
                /*
                 * Failed to get remote_oid. If o->remote_ref looks like an
                 * unborn ref, perform the merge using an empty notes tree.
@@ -600,7 +607,7 @@ int notes_merge(struct notes_merge_options *o,
        assert(local && remote);
 
        /* Find merge bases */
-       bases = get_merge_bases(local, remote);
+       bases = repo_get_merge_bases(the_repository, local, remote);
        if (!bases) {
                base_oid = null_oid();
                base_tree_oid = the_hash_algo->empty_tree;
@@ -678,7 +685,8 @@ int notes_merge_commit(struct notes_merge_options *o,
        DIR *dir;
        struct dirent *e;
        struct strbuf path = STRBUF_INIT;
-       const char *buffer = get_commit_buffer(partial_commit, NULL);
+       const char *buffer = repo_get_commit_buffer(the_repository,
+                                                   partial_commit, NULL);
        const char *msg = strstr(buffer, "\n\n");
        int baselen;
 
@@ -725,7 +733,7 @@ int notes_merge_commit(struct notes_merge_options *o,
 
        create_notes_commit(o->repo, partial_tree, partial_commit->parents, msg,
                            strlen(msg), result_oid);
-       unuse_commit_buffer(partial_commit, buffer);
+       repo_unuse_commit_buffer(the_repository, partial_commit, buffer);
        if (o->verbosity >= 4)
                printf("Finalized notes merge commit: %s\n",
                        oid_to_hex(result_oid));
index d7d18e30f5a281278aa87fd64a4e47da8410a5eb..97c031c26ec7c7c2fdade8478fa039d470820bad 100644 (file)
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "commit.h"
+#include "environment.h"
+#include "gettext.h"
 #include "refs.h"
 #include "notes-utils.h"
 #include "repository.h"
+#include "strbuf.h"
 
 void create_notes_commit(struct repository *r,
                         struct notes_tree *t,
@@ -23,7 +26,7 @@ void create_notes_commit(struct repository *r,
                struct object_id parent_oid;
                if (!read_ref(t->ref, &parent_oid)) {
                        struct commit *parent = lookup_commit(r, &parent_oid);
-                       if (parse_commit(parent))
+                       if (repo_parse_commit(r, parent))
                                die("Failed to find/parse commit %s", t->ref);
                        commit_list_insert(parent, &parents);
                }
@@ -91,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 f2805d51bb15131c46d41fa9554c43ab2e9a492d..1ef2a331ce9302e58cb2078e58b7b40a94972b3e 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
+#include "hex.h"
 #include "notes.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "tree.h"
 #include "utf8.h"
@@ -752,7 +755,7 @@ static int write_each_non_note_until(const char *note_path,
        return 0;
 }
 
-static int write_each_note(const struct object_id *object_oid,
+static int write_each_note(const struct object_id *object_oid UNUSED,
                const struct object_id *note_oid, char *note_path,
                void *cb_data)
 {
@@ -780,13 +783,14 @@ struct note_delete_list {
 };
 
 static int prune_notes_helper(const struct object_id *object_oid,
-               const struct object_id *note_oid, char *note_path,
-               void *cb_data)
+                             const struct object_id *note_oid UNUSED,
+                             char *note_path UNUSED,
+                             void *cb_data)
 {
        struct note_delete_list **l = (struct note_delete_list **) cb_data;
        struct note_delete_list *n;
 
-       if (has_object_file(object_oid))
+       if (repo_has_object_file(the_repository, object_oid))
                return 0; /* nothing to do for this note */
 
        /* failed to find object => prune this note */
@@ -807,13 +811,15 @@ int combine_notes_concatenate(struct object_id *cur_oid,
 
        /* read in both note blob objects */
        if (!is_null_oid(new_oid))
-               new_msg = read_object_file(new_oid, &new_type, &new_len);
+               new_msg = repo_read_object_file(the_repository, new_oid,
+                                               &new_type, &new_len);
        if (!new_msg || !new_len || new_type != OBJ_BLOB) {
                free(new_msg);
                return 0;
        }
        if (!is_null_oid(cur_oid))
-               cur_msg = read_object_file(cur_oid, &cur_type, &cur_len);
+               cur_msg = repo_read_object_file(the_repository, cur_oid,
+                                               &cur_type, &cur_len);
        if (!cur_msg || !cur_len || cur_type != OBJ_BLOB) {
                free(cur_msg);
                free(new_msg);
@@ -848,8 +854,8 @@ int combine_notes_overwrite(struct object_id *cur_oid,
        return 0;
 }
 
-int combine_notes_ignore(struct object_id *cur_oid,
-                        const struct object_id *new_oid)
+int combine_notes_ignore(struct object_id *cur_oid UNUSED,
+                        const struct object_id *new_oid UNUSED)
 {
        return 0;
 }
@@ -869,7 +875,7 @@ static int string_list_add_note_lines(struct string_list *list,
                return 0;
 
        /* read_sha1_file NUL-terminates */
-       data = read_object_file(oid, &t, &len);
+       data = repo_read_object_file(the_repository, oid, &t, &len);
        if (t != OBJ_BLOB || !data || !len) {
                free(data);
                return t != OBJ_BLOB || !data;
@@ -944,7 +950,7 @@ void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
                for_each_glob_ref(string_list_add_one_ref, glob, list);
        } else {
                struct object_id oid;
-               if (get_oid(glob, &oid))
+               if (repo_get_oid(the_repository, glob, &oid))
                        warning("notes ref %s is invalid", glob);
                if (!unsorted_string_list_has_string(list, glob))
                        string_list_append(list, glob);
@@ -958,7 +964,7 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
        char *globs_copy = xstrdup(globs);
        int i;
 
-       string_list_split_in_place(&split, globs_copy, ':', -1);
+       string_list_split_in_place(&split, globs_copy, ":", -1);
        string_list_remove_empty_items(&split, 0);
 
        for (i = 0; i < split.nr; i++)
@@ -968,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;
 
@@ -1014,14 +1022,14 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
        t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));
        t->first_non_note = NULL;
        t->prev_non_note = NULL;
-       t->ref = xstrdup_or_null(notes_ref);
+       t->ref = xstrdup(notes_ref);
        t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;
        t->combine_notes = combine_notes;
        t->initialized = 1;
        t->dirty = 0;
 
-       if (flags & NOTES_INIT_EMPTY || !notes_ref ||
-           get_oid_treeish(notes_ref, &object_oid))
+       if (flags & NOTES_INIT_EMPTY ||
+           repo_get_oid_treeish(the_repository, notes_ref, &object_oid))
                return;
        if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
                die("Cannot use notes ref %s", notes_ref);
@@ -1264,7 +1272,7 @@ static void format_note(struct notes_tree *t, const struct object_id *object_oid
        if (!oid)
                return;
 
-       if (!(msg = read_object_file(oid, &type, &msglen)) || type != OBJ_BLOB) {
+       if (!(msg = repo_read_object_file(the_repository, oid, &type, &msglen)) || type != OBJ_BLOB) {
                free(msg);
                return;
        }
@@ -1348,7 +1356,7 @@ void expand_loose_notes_ref(struct strbuf *sb)
 {
        struct object_id object;
 
-       if (get_oid(sb->buf, &object)) {
+       if (repo_get_oid(the_repository, sb->buf, &object)) {
                /* fallback to expand_notes_ref */
                expand_notes_ref(sb);
        }
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 939865c1ae0566ba577861505f2ecf2e9fd19eeb..7dc0c4bfbba87d1a9f42e3274764f7e07cc74c52 100644 (file)
@@ -6,8 +6,13 @@
  * This handles basic git object files - packing, unpacking,
  * creation etc.
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
+#include "convert.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "string-list.h"
 #include "lockfile.h"
 #include "delta.h"
 #include "mergesort.h"
 #include "quote.h"
 #include "packfile.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"
 
@@ -267,7 +276,7 @@ int hash_algo_by_length(int len)
 
 /*
  * This is meant to hold a *small* number of objects that you would
- * want read_object_file() to be able to return, but yet you do not want
+ * want repo_read_object_file() to be able to return, but yet you do not want
  * to write them into the object store (e.g. a browse-only
  * application).
  */
@@ -944,6 +953,12 @@ void prepare_alt_odb(struct repository *r)
        r->objects->loaded_alternates = 1;
 }
 
+int has_alt_odb(struct repository *r)
+{
+       prepare_alt_odb(r);
+       return !!r->objects->odb->next;
+}
+
 /* Returns 1 if we have successfully freshened the file, 0 otherwise. */
 static int freshen_file(const char *fn)
 {
@@ -1678,7 +1693,7 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
        struct cached_object *co;
 
        hash_object_file(the_hash_algo, buf, len, type, oid);
-       if (has_object_file_with_flags(oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
+       if (repo_has_object_file_with_flags(the_repository, oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
            find_cached_object(oid))
                return 0;
        ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
@@ -2291,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);
@@ -2644,7 +2659,8 @@ int for_each_loose_object(each_loose_object_fn cb, void *data,
        return 0;
 }
 
-static int append_loose_object(const struct object_id *oid, const char *path,
+static int append_loose_object(const struct object_id *oid,
+                              const char *path UNUSED,
                               void *data)
 {
        oidtree_insert(data, oid);
diff --git a/object-file.h b/object-file.h
new file mode 100644 (file)
index 0000000..d641461
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef OBJECT_FILE_H
+#define OBJECT_FILE_H
+
+#include "git-zlib.h"
+#include "object.h"
+
+struct index_state;
+
+/*
+ * Set this to 0 to prevent oid_object_info_extended() from fetching missing
+ * blobs. This has a difference only if extensions.partialClone is set.
+ *
+ * Its default value is 1.
+ */
+extern int fetch_if_missing;
+
+#define HASH_WRITE_OBJECT 1
+#define HASH_FORMAT_CHECK 2
+#define HASH_RENORMALIZE  4
+#define HASH_SILENT 8
+int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
+int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
+
+/*
+ * Create the directory containing the named path, using care to be
+ * somewhat safe against races. Return one of the scld_error values to
+ * indicate success/failure. On error, set errno to describe the
+ * problem.
+ *
+ * SCLD_VANISHED indicates that one of the ancestor directories of the
+ * path existed at one point during the function call and then
+ * suddenly vanished, probably because another process pruned the
+ * directory while we were working.  To be robust against this kind of
+ * race, callers might want to try invoking the function again when it
+ * returns SCLD_VANISHED.
+ *
+ * safe_create_leading_directories() temporarily changes path while it
+ * is working but restores it before returning.
+ * safe_create_leading_directories_const() doesn't modify path, even
+ * temporarily. Both these variants adjust the permissions of the
+ * created directories to honor core.sharedRepository, so they are best
+ * suited for files inside the git dir. For working tree files, use
+ * safe_create_leading_directories_no_share() instead, as it ignores
+ * the core.sharedRepository setting.
+ */
+enum scld_error {
+       SCLD_OK = 0,
+       SCLD_FAILED = -1,
+       SCLD_PERMS = -2,
+       SCLD_EXISTS = -3,
+       SCLD_VANISHED = -4
+};
+enum scld_error safe_create_leading_directories(char *path);
+enum scld_error safe_create_leading_directories_const(const char *path);
+enum scld_error safe_create_leading_directories_no_share(char *path);
+
+int mkdir_in_gitdir(const char *path);
+
+int git_open_cloexec(const char *name, int flags);
+#define git_open(name) git_open_cloexec(name, O_RDONLY)
+
+/**
+ * unpack_loose_header() initializes the data stream needed to unpack
+ * a loose object header.
+ *
+ * Returns:
+ *
+ * - ULHR_OK on success
+ * - ULHR_BAD on error
+ * - ULHR_TOO_LONG if the header was too long
+ *
+ * It will only parse up to MAX_HEADER_LEN bytes unless an optional
+ * "hdrbuf" argument is non-NULL. This is intended for use with
+ * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error)
+ * reporting. The full header will be extracted to "hdrbuf" for use
+ * with parse_loose_header(), ULHR_TOO_LONG will still be returned
+ * from this function to indicate that the header was too long.
+ */
+enum unpack_loose_header_result {
+       ULHR_OK,
+       ULHR_BAD,
+       ULHR_TOO_LONG,
+};
+enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
+                                                   unsigned char *map,
+                                                   unsigned long mapsize,
+                                                   void *buffer,
+                                                   unsigned long bufsiz,
+                                                   struct strbuf *hdrbuf);
+
+/**
+ * parse_loose_header() parses the starting "<type> <len>\0" of an
+ * object. If it doesn't follow that format -1 is returned. To check
+ * the validity of the <type> populate the "typep" in the "struct
+ * object_info". It will be OBJ_BAD if the object type is unknown. The
+ * parsed <len> can be retrieved via "oi->sizep", and from there
+ * passed to unpack_loose_rest().
+ */
+struct object_info;
+int parse_loose_header(const char *hdr, struct object_info *oi);
+
+/**
+ * With in-core object data in "buf", rehash it to make sure the
+ * object name actually matches "oid" to detect object corruption.
+ *
+ * A negative value indicates an error, usually that the OID is not
+ * what we expected, but it might also indicate another error.
+ */
+int check_object_signature(struct repository *r, const struct object_id *oid,
+                          void *map, unsigned long size,
+                          enum object_type type);
+
+/**
+ * A streaming version of check_object_signature().
+ * Try reading the object named with "oid" using
+ * the streaming interface and rehash it to do the same.
+ */
+int stream_object_signature(struct repository *r, const struct object_id *oid);
+
+int finalize_object_file(const char *tmpfile, const char *filename);
+
+/* Helper to check and "touch" a file */
+int check_and_freshen_file(const char *fn, int freshen);
+
+void *read_object_with_reference(struct repository *r,
+                                const struct object_id *oid,
+                                enum object_type required_type,
+                                unsigned long *size,
+                                struct object_id *oid_ret);
+
+#endif /* OBJECT_FILE_H */
index 2dd1a0f56e1e442dec47dfbbcdd46d58aecc812c..0bfa29dbbfe9b489e454c03b419092294427425d 100644 (file)
@@ -1,5 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "object-name.h"
+#include "advice.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "tag.h"
 #include "commit.h"
 #include "tree.h"
@@ -9,9 +14,13 @@
 #include "remote.h"
 #include "dir.h"
 #include "oid-array.h"
+#include "oidtree.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "pretty.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
 #include "repository.h"
+#include "setup.h"
 #include "submodule.h"
 #include "midx.h"
 #include "commit-reach.h"
@@ -223,7 +232,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
 
 static int disambiguate_commit_only(struct repository *r,
                                    const struct object_id *oid,
-                                   void *cb_data_unused)
+                                   void *cb_data UNUSED)
 {
        int kind = oid_object_info(r, oid, NULL);
        return kind == OBJ_COMMIT;
@@ -231,7 +240,7 @@ static int disambiguate_commit_only(struct repository *r,
 
 static int disambiguate_committish_only(struct repository *r,
                                        const struct object_id *oid,
-                                       void *cb_data_unused)
+                                       void *cb_data UNUSED)
 {
        struct object *obj;
        int kind;
@@ -251,7 +260,7 @@ static int disambiguate_committish_only(struct repository *r,
 
 static int disambiguate_tree_only(struct repository *r,
                                  const struct object_id *oid,
-                                 void *cb_data_unused)
+                                 void *cb_data UNUSED)
 {
        int kind = oid_object_info(r, oid, NULL);
        return kind == OBJ_TREE;
@@ -259,7 +268,7 @@ static int disambiguate_tree_only(struct repository *r,
 
 static int disambiguate_treeish_only(struct repository *r,
                                     const struct object_id *oid,
-                                    void *cb_data_unused)
+                                    void *cb_data UNUSED)
 {
        struct object *obj;
        int kind;
@@ -279,7 +288,7 @@ static int disambiguate_treeish_only(struct repository *r,
 
 static int disambiguate_blob_only(struct repository *r,
                                  const struct object_id *oid,
-                                 void *cb_data_unused)
+                                 void *cb_data UNUSED)
 {
        int kind = oid_object_info(r, oid, NULL);
        return kind == OBJ_BLOB;
@@ -394,8 +403,10 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
                if (commit) {
                        struct pretty_print_context pp = {0};
                        pp.date_mode.type = DATE_SHORT;
-                       format_commit_message(commit, "%ad", &date, &pp);
-                       format_commit_message(commit, "%s", &msg, &pp);
+                       repo_format_commit_message(the_repository, commit,
+                                                  "%ad", &date, &pp);
+                       repo_format_commit_message(the_repository, commit,
+                                                  "%s", &msg, &pp);
                }
 
                /*
@@ -473,7 +484,7 @@ static int collect_ambiguous(const struct object_id *oid, void *data)
        return 0;
 }
 
-static int repo_collect_ambiguous(struct repository *r,
+static int repo_collect_ambiguous(struct repository *r UNUSED,
                                  const struct object_id *oid,
                                  void *data)
 {
@@ -665,7 +676,7 @@ static int extend_abbrev_len(const struct object_id *oid, void *cb_data)
        return 0;
 }
 
-static int repo_extend_abbrev_len(struct repository *r,
+static int repo_extend_abbrev_len(struct repository *r UNUSED,
                                  const struct object_id *oid,
                                  void *cb_data)
 {
@@ -758,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)
 {
@@ -898,6 +924,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
        char *real_ref = NULL;
        int refs_found = 0;
        int at, reflog_len, nth_prior = 0;
+       int fatal = !(flags & GET_OID_QUIETLY);
 
        if (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {
                if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
@@ -952,11 +979,11 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
 
        if (!len && reflog_len)
                /* allow "@{...}" to mean the current branch reflog */
-               refs_found = repo_dwim_ref(r, "HEAD", 4, oid, &real_ref, 0);
+               refs_found = repo_dwim_ref(r, "HEAD", 4, oid, &real_ref, !fatal);
        else if (reflog_len)
                refs_found = repo_dwim_log(r, str, len, oid, &real_ref);
        else
-               refs_found = repo_dwim_ref(r, str, len, oid, &real_ref, 0);
+               refs_found = repo_dwim_ref(r, str, len, oid, &real_ref, !fatal);
 
        if (!refs_found)
                return -1;
@@ -1036,7 +1063,7 @@ static enum get_oid_result get_parent(struct repository *r,
        if (ret)
                return ret;
        commit = lookup_commit_reference(r, &oid);
-       if (parse_commit(commit))
+       if (repo_parse_commit(r, commit))
                return MISSING_OBJECT;
        if (!idx) {
                oidcpy(result, &commit->object.oid);
@@ -1070,7 +1097,7 @@ static enum get_oid_result get_nth_ancestor(struct repository *r,
                return MISSING_OBJECT;
 
        while (generation--) {
-               if (parse_commit(commit) || !commit->parents)
+               if (repo_parse_commit(r, commit) || !commit->parents)
                        return MISSING_OBJECT;
                commit = commit->parents->item;
        }
@@ -1361,10 +1388,10 @@ static int get_oid_oneline(struct repository *r,
                commit = pop_most_recent_commit(&list, ONELINE_SEEN);
                if (!parse_object(r, &commit->object.oid))
                        continue;
-               buf = get_commit_buffer(commit, NULL);
+               buf = repo_get_commit_buffer(r, commit, NULL);
                p = strstr(buf, "\n\n");
                matches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));
-               unuse_commit_buffer(commit, buf);
+               repo_unuse_commit_buffer(r, commit, buf);
 
                if (matches) {
                        oidcpy(oid, &commit->object.oid);
@@ -1666,7 +1693,8 @@ void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed)
        struct interpret_branch_name_options options = {
                .allowed = allowed
        };
-       int used = interpret_branch_name(name, len, sb, &options);
+       int used = repo_interpret_branch_name(the_repository, name, len, sb,
+                                             &options);
 
        if (used < 0)
                used = 0;
@@ -1719,7 +1747,7 @@ int get_oidf(struct object_id *oid, const char *fmt, ...)
        strbuf_vaddf(&sb, fmt, ap);
        va_end(ap);
 
-       ret = get_oid(sb.buf, oid);
+       ret = repo_get_oid(the_repository, sb.buf, oid);
        strbuf_release(&sb);
 
        return ret;
diff --git a/object-name.h b/object-name.h
new file mode 100644 (file)
index 0000000..9ae5223
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef OBJECT_NAME_H
+#define OBJECT_NAME_H
+
+#include "object.h"
+#include "strbuf.h"
+
+struct object_id;
+struct repository;
+
+struct object_context {
+       unsigned short mode;
+       /*
+        * symlink_path is only used by get_tree_entry_follow_symlinks,
+        * and only for symlinks that point outside the repository.
+        */
+       struct strbuf symlink_path;
+       /*
+        * If GET_OID_RECORD_PATH is set, this will record path (if any)
+        * found when resolving the name. The caller is responsible for
+        * releasing the memory.
+        */
+       char *path;
+};
+
+/*
+ * Return an abbreviated sha1 unique within this repository's object database.
+ * The result will be at least `len` characters long, and will be NUL
+ * terminated.
+ *
+ * The non-`_r` version returns a static buffer which remains valid until 4
+ * more calls to repo_find_unique_abbrev are made.
+ *
+ * The `_r` variant writes to a buffer supplied by the caller, which must be at
+ * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes
+ * written (excluding the NUL terminator).
+ *
+ * Note that while this version avoids the static buffer, it is not fully
+ * reentrant, as it calls into other non-reentrant git code.
+ */
+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, ...);
+int repo_get_oid_commit(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_committish(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_tree(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_treeish(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_blob(struct repository *r, const char *str, struct object_id *oid);
+int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid);
+void maybe_die_on_misspelt_object_name(struct repository *repo,
+                                      const char *name,
+                                      const char *prefix);
+enum get_oid_result get_oid_with_context(struct repository *repo, const char *str,
+                                        unsigned flags, struct object_id *oid,
+                                        struct object_context *oc);
+
+
+typedef int each_abbrev_fn(const struct object_id *oid, void *);
+int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
+
+int set_disambiguate_hint_config(const char *var, const char *value);
+
+/*
+ * This reads short-hand syntax that not only evaluates to a commit
+ * object name, but also can act as if the end user spelled the name
+ * of the branch from the command line.
+ *
+ * - "@{-N}" finds the name of the Nth previous branch we were on, and
+ *   places the name of the branch in the given buf and returns the
+ *   number of characters parsed if successful.
+ *
+ * - "<branch>@{upstream}" finds the name of the other ref that
+ *   <branch> is configured to merge with (missing <branch> defaults
+ *   to the current branch), and places the name of the branch in the
+ *   given buf and returns the number of characters parsed if
+ *   successful.
+ *
+ * If the input is not of the accepted format, it returns a negative
+ * number to signal an error.
+ *
+ * If the input was ok but there are not N branch switches in the
+ * reflog, it returns 0.
+ */
+#define INTERPRET_BRANCH_LOCAL (1<<0)
+#define INTERPRET_BRANCH_REMOTE (1<<1)
+#define INTERPRET_BRANCH_HEAD (1<<2)
+struct interpret_branch_name_options {
+       /*
+        * If "allowed" is non-zero, it is a treated as a bitfield of allowable
+        * expansions: local branches ("refs/heads/"), remote branches
+        * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is
+        * allowed, even ones to refs outside of those namespaces.
+        */
+       unsigned allowed;
+
+       /*
+        * If ^{upstream} or ^{push} (or equivalent) is requested, and the
+        * branch in question does not have such a reference, return -1 instead
+        * of die()-ing.
+        */
+       unsigned nonfatal_dangling_mark : 1;
+};
+int repo_interpret_branch_name(struct repository *r,
+                              const char *str, int len,
+                              struct strbuf *buf,
+                              const struct interpret_branch_name_options *options);
+
+struct object *repo_peel_to_type(struct repository *r,
+                                const char *name, int namelen,
+                                struct object *o, enum object_type);
+
+/* Convert to/from hex/sha1 representation */
+#define MINIMUM_ABBREV minimum_abbrev
+#define DEFAULT_ABBREV default_abbrev
+
+/* used when the code does not know or care what the default abbrev is */
+#define FALLBACK_DEFAULT_ABBREV 7
+
+#endif /* OBJECT_NAME_H */
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 1a713d89d7c872bfd253c4a88bec6efa8ed597f8..1b3e3d7d0145be18b523ea836aaac3e84c06af4e 100644 (file)
 #ifndef OBJECT_STORE_H
 #define OBJECT_STORE_H
 
-#include "cache.h"
-#include "oidmap.h"
-#include "list.h"
-#include "oid-array.h"
-#include "strbuf.h"
-#include "thread-utils.h"
 #include "khash.h"
 #include "dir.h"
-#include "oidtree.h"
-#include "oidset.h"
-
-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);
-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
-        * 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);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define read_object_file(oid, type, size) repo_read_object_file(the_repository, oid, type, size)
-#endif
-
-/* 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);
-
-/*
- * 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);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define has_object_file(oid) repo_has_object_file(the_repository, oid)
-#define has_object_file_with_flags(oid, flags) repo_has_object_file_with_flags(the_repository, oid, flags)
-#endif
-
-/*
- * 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_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);
-}
-
-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);
-
-/*
- * 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 344087de4de5184fcbfb599277180cec8f39c474..2c61e4c86217e633d2e28acd0b3ae654584ede7d 100644 (file)
--- a/object.c
+++ b/object.c
@@ -1,8 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
 #include "object.h"
 #include "replace-object.h"
+#include "object-file.h"
 #include "object-store.h"
 #include "blob.h"
+#include "statinfo.h"
 #include "tree.h"
 #include "commit.h"
 #include "tag.h"
@@ -353,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 31ebe114585bb14cb95f4c74486635754d199955..114d45954d082229ed747dee16f2510387145771 100644 (file)
--- a/object.h
+++ b/object.h
@@ -1,9 +1,10 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
-#include "cache.h"
+#include "hash-ll.h"
 
 struct buffer_slab;
+struct repository;
 
 struct parsed_object_pool {
        struct object **obj_hash;
@@ -57,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
@@ -81,6 +84,70 @@ struct object_array {
  */
 #define FLAG_BITS  28
 
+#define TYPE_BITS 3
+
+/*
+ * Values in this enum (except those outside the 3 bit range) are part
+ * of pack file format. See gitformat-pack(5) for more information.
+ */
+enum object_type {
+       OBJ_BAD = -1,
+       OBJ_NONE = 0,
+       OBJ_COMMIT = 1,
+       OBJ_TREE = 2,
+       OBJ_BLOB = 3,
+       OBJ_TAG = 4,
+       /* 5 for future expansion */
+       OBJ_OFS_DELTA = 6,
+       OBJ_REF_DELTA = 7,
+       OBJ_ANY,
+       OBJ_MAX
+};
+
+/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */
+#define S_IFINVALID     0030000
+
+/*
+ * A "directory link" is a link to another git directory.
+ *
+ * The value 0160000 is not normally a valid mode, and
+ * also just happens to be S_IFDIR + S_IFLNK
+ */
+#define S_IFGITLINK    0160000
+#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
+
+#define S_ISSPARSEDIR(m) ((m) == S_IFDIR)
+
+static inline enum object_type object_type(unsigned int mode)
+{
+       return S_ISDIR(mode) ? OBJ_TREE :
+               S_ISGITLINK(mode) ? OBJ_COMMIT :
+               OBJ_BLOB;
+}
+
+#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
+static inline unsigned int create_ce_mode(unsigned int mode)
+{
+       if (S_ISLNK(mode))
+               return S_IFLNK;
+       if (S_ISSPARSEDIR(mode))
+               return S_IFDIR;
+       if (S_ISDIR(mode) || S_ISGITLINK(mode))
+               return S_IFGITLINK;
+       return S_IFREG | ce_permissions(mode);
+}
+
+static inline unsigned int canon_mode(unsigned int mode)
+{
+       if (S_ISREG(mode))
+               return S_IFREG | ce_permissions(mode);
+       if (S_ISLNK(mode))
+               return S_IFLNK;
+       if (S_ISDIR(mode))
+               return S_IFDIR;
+       return S_IFGITLINK;
+}
+
 /*
  * The object type is stored in 3 bits.
  */
index 73ba76e9e9a223306a03c3d04123c0c4af4aeda2..8e4717746c3183bd47c3c746c747efd83c61168c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "oid-array.h"
 #include "hash-lookup.h"
 
index 49965fe856814393c9381788dced2b05d35aed1f..8b1bc4dec9496e3b49ba064cc0936925625e5c79 100644 (file)
--- a/oidmap.c
+++ b/oidmap.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash.h"
 #include "oidmap.h"
 
 static int oidmap_neq(const void *hashmap_cmp_fn_data UNUSED,
index c66a83ab1d6891dbe6916d13339b64456b8cc440..05c673eb7c1163d912dd7e54466ae9931be5426b 100644 (file)
--- a/oidmap.h
+++ b/oidmap.h
@@ -1,7 +1,7 @@
 #ifndef OIDMAP_H
 #define OIDMAP_H
 
-#include "cache.h"
+#include "hash-ll.h"
 #include "hashmap.h"
 
 /*
index b36a2bae86470236a51ffe6bec7792222de478fe..d1e5376316ecd5f9dcf549e1067697283bdc712c 100644 (file)
--- a/oidset.c
+++ b/oidset.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "oidset.h"
+#include "hex.h"
+#include "strbuf.h"
 
 void oidset_init(struct oidset *set, size_t initial_size)
 {
index 0d39389bee29be3f0496185331df1ac85f87003b..daef175dc71d6c7d55fc89ef1e286334afbe00b7 100644 (file)
--- a/oidtree.c
+++ b/oidtree.c
@@ -2,8 +2,8 @@
  * A wrapper around cbtree which stores oids
  * May be used to replace oid-array for prefix (abbreviation) matches
  */
+#include "git-compat-util.h"
 #include "oidtree.h"
-#include "alloc.h"
 #include "hash.h"
 
 struct oidtree_iter_data {
index 77898f510a12272ae2302805896eaf9eecb5ce7d..55c83513fdd5f3823a3b3a430ce814094deed5ba 100644 (file)
--- a/oidtree.h
+++ b/oidtree.h
@@ -2,7 +2,7 @@
 #define OIDTREE_H
 
 #include "cbtree.h"
-#include "hash.h"
+#include "hash-ll.h"
 #include "mem-pool.h"
 
 struct oidtree {
index 914026f5d80f876c8a7c28a914a58295a5a72346..2992079dd97d75892f4f411cd4a979f459d68170 100644 (file)
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "commit-graph.h"
 #include "repository.h"
 
index 99da1d0fd385eb3bc0c7f0b4a0b8cd167e0cb5e0..150c0f5fa2d7ec2b9dd6a14f6000e5b58b753aa9 100644 (file)
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "packfile.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
index 0c3d777aac8de618a36777c5c82edae302c1bbcc..3e190214d1487e4bd1f04315698e0f041402648e 100644 (file)
@@ -1,4 +1,5 @@
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "object-store-ll.h"
 #include "packfile.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
index cfa67a510fd9a98ec5461084d08373086de858d5..f6757c3cbf2019b7cf41b3d82e0861138c92c075 100644 (file)
@@ -1,5 +1,8 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "tag.h"
 #include "diff.h"
 #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"
+#include "tree.h"
+#include "tree-walk.h"
 
 struct bitmapped_commit {
        struct commit *commit;
@@ -425,7 +432,8 @@ static int fill_bitmap_commit(struct bb_commit *ent,
                if (!found)
                        return -1;
                bitmap_set(ent->bitmap, pos);
-               prio_queue_put(tree_queue, get_commit_tree(c));
+               prio_queue_put(tree_queue,
+                              repo_get_commit_tree(the_repository, c));
 
                for (p = c->parents; p; p = p->next) {
                        pos = find_object_pos(&p->item->object.oid, &found);
index d2a42abf28cc7246b3d076b1c855a350edcded70..6afc03d1e4c39e53c1c48deb51c16d65667979e8 100644 (file)
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "commit.h"
+#include "gettext.h"
+#include "hex.h"
 #include "strbuf.h"
 #include "tag.h"
 #include "diff.h"
@@ -12,7 +14,9 @@
 #include "pack-objects.h"
 #include "packfile.h"
 #include "repository.h"
-#include "object-store.h"
+#include "trace2.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "list-objects-filter-options.h"
 #include "midx.h"
 #include "config.h"
@@ -376,15 +380,17 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
                goto cleanup;
        }
 
-       if (load_midx_revindex(bitmap_git->midx) < 0) {
+       if (load_midx_revindex(bitmap_git->midx)) {
                warning(_("multi-pack bitmap is missing required reverse index"));
                goto cleanup;
        }
 
        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)];
@@ -460,7 +466,7 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
        return 0;
 }
 
-static int load_reverse_index(struct bitmap_index *bitmap_git)
+static int load_reverse_index(struct repository *r, struct bitmap_index *bitmap_git)
 {
        if (bitmap_is_midx(bitmap_git)) {
                uint32_t i;
@@ -474,23 +480,23 @@ static int load_reverse_index(struct bitmap_index *bitmap_git)
                 * since we will need to make use of them in pack-objects.
                 */
                for (i = 0; i < bitmap_git->midx->num_packs; i++) {
-                       ret = load_pack_revindex(bitmap_git->midx->packs[i]);
+                       ret = load_pack_revindex(r, bitmap_git->midx->packs[i]);
                        if (ret)
                                return ret;
                }
                return 0;
        }
-       return load_pack_revindex(bitmap_git->pack);
+       return load_pack_revindex(r, bitmap_git->pack);
 }
 
-static int load_bitmap(struct bitmap_index *bitmap_git)
+static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git)
 {
        assert(bitmap_git->map);
 
        bitmap_git->bitmaps = kh_init_oid_map();
        bitmap_git->ext_index.positions = kh_init_oid_pos();
 
-       if (load_reverse_index(bitmap_git))
+       if (load_reverse_index(r, bitmap_git))
                goto failed;
 
        if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) ||
@@ -577,7 +583,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
 {
        struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
 
-       if (!open_bitmap(r, bitmap_git) && !load_bitmap(bitmap_git))
+       if (!open_bitmap(r, bitmap_git) && !load_bitmap(r, bitmap_git))
                return bitmap_git;
 
        free_bitmap_index(bitmap_git);
@@ -586,9 +592,10 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
 
 struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx)
 {
+       struct repository *r = the_repository;
        struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
 
-       if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(bitmap_git))
+       if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git))
                return bitmap_git;
 
        free_bitmap_index(bitmap_git);
@@ -951,7 +958,8 @@ static void show_object(struct object *object, const char *name, void *data_)
        bitmap_set(data->base, bitmap_pos);
 }
 
-static void show_commit(struct commit *commit, void *data)
+static void show_commit(struct commit *commit UNUSED,
+                       void *data UNUSED)
 {
 }
 
@@ -1036,6 +1044,160 @@ 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,
+                                const char *name, void *data)
+{
+       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,
@@ -1102,33 +1264,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;
@@ -1145,7 +1293,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];
@@ -1324,7 +1472,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))
@@ -1415,7 +1563,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) &&
@@ -1521,6 +1669,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;
@@ -1571,13 +1720,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)
@@ -1588,21 +1745,35 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
         * from disk. this is the point of no return; after this the rev_list
         * becomes invalidated and we must perform the revwalk through bitmaps
         */
-       if (load_bitmap(bitmap_git) < 0)
+       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)
@@ -1738,6 +1909,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
                                       uint32_t *entries,
                                       struct bitmap **reuse_out)
 {
+       struct repository *r = the_repository;
        struct packed_git *pack;
        struct bitmap *result = bitmap_git->result;
        struct bitmap *reuse;
@@ -1748,7 +1920,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
 
        assert(result);
 
-       load_reverse_index(bitmap_git);
+       load_reverse_index(r, bitmap_git);
 
        if (bitmap_is_midx(bitmap_git))
                pack = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)];
@@ -1865,7 +2037,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++;
        }
 
@@ -1940,7 +2113,8 @@ static void test_bitmap_type(struct bitmap_test_data *tdata,
                    type_name(bitmap_type));
 }
 
-static void test_show_object(struct object *object, const char *name,
+static void test_show_object(struct object *object,
+                            const char *name UNUSED,
                             void *data)
 {
        struct bitmap_test_data *tdata = data;
@@ -2127,12 +2301,13 @@ int rebuild_bitmap(const uint32_t *reposition,
 uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
                                struct packing_data *mapping)
 {
+       struct repository *r = the_repository;
        uint32_t i, num_objects;
        uint32_t *reposition;
 
        if (!bitmap_is_midx(bitmap_git))
-               load_reverse_index(bitmap_git);
-       else if (load_midx_revindex(bitmap_git->midx) < 0)
+               load_reverse_index(r, bitmap_git);
+       else if (load_midx_revindex(bitmap_git->midx))
                BUG("rebuild_existing_bitmaps: missing required rev-cache "
                    "extension");
 
@@ -2277,7 +2452,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)
@@ -2314,7 +2490,11 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git)
 
 const struct string_list *bitmap_preferred_tips(struct repository *r)
 {
-       return repo_config_get_value_multi(r, "pack.preferbitmaptips");
+       const struct string_list *dest;
+
+       if (!repo_config_get_string_multi(r, "pack.preferbitmaptips", &dest))
+               return dest;
+       return NULL;
 }
 
 int bitmap_is_preferred_refname(struct repository *r, const char *refname)
@@ -2332,3 +2512,48 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname)
 
        return 0;
 }
+
+static int verify_bitmap_file(const char *name)
+{
+       struct stat st;
+       unsigned char *data;
+       int fd = git_open(name);
+       int res = 0;
+
+       /* It is OK to not have the file. */
+       if (fd < 0 || fstat(fd, &st)) {
+               if (fd >= 0)
+                       close(fd);
+               return 0;
+       }
+
+       data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       close(fd);
+       if (!hashfile_checksum_valid(data, st.st_size))
+               res = error(_("bitmap file '%s' has invalid checksum"),
+                           name);
+
+       munmap(data, st.st_size);
+       return res;
+}
+
+int verify_bitmap_files(struct repository *r)
+{
+       int res = 0;
+
+       for (struct multi_pack_index *m = get_multi_pack_index(r);
+            m; m = m->next) {
+               char *midx_bitmap_name = midx_bitmap_filename(m);
+               res |= verify_bitmap_file(midx_bitmap_name);
+               free(midx_bitmap_name);
+       }
+
+       for (struct packed_git *p = get_all_packs(r);
+            p; p = p->next) {
+               char *pack_bitmap_name = pack_bitmap_filename(p);
+               res |= verify_bitmap_file(pack_bitmap_name);
+               free(pack_bitmap_name);
+       }
+
+       return res;
+}
index f0180b5276b15d6567eda9984637333811fa851b..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);
@@ -111,4 +115,6 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git);
 const struct string_list *bitmap_preferred_tips(struct repository *r);
 int bitmap_is_preferred_refname(struct repository *r, const char *refname);
 
+int verify_bitmap_files(struct repository *r);
+
 #endif
index bfb593ba7261a18a8283604f4e1cfdd10eb978f6..977f619618e0a9b97044f0b07e5617d3b3e1839b 100644 (file)
@@ -1,10 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "hex.h"
 #include "repository.h"
 #include "pack.h"
 #include "pack-revindex.h"
 #include "progress.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 
 struct idx_entry {
        off_t                offset;
index 0f9785fc5e4ed9c26f7c1f5503395e74da0d74b3..cdf30b8d2b0e809db7ee7e219b39863fad702bd4 100644 (file)
@@ -1,7 +1,10 @@
 #include "git-compat-util.h"
+#include "gettext.h"
 #include "pack-mtimes.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "packfile.h"
+#include "strbuf.h"
 
 static char *pack_mtimes_filename(struct packed_git *p)
 {
index cc957b3e852716541f764a40641462cb39fe0407..107327cec0bc5202051b6139e926fd27a1ce6c9c 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef PACK_MTIMES_H
 #define PACK_MTIMES_H
 
-#include "git-compat-util.h"
-
 #define MTIMES_SIGNATURE 0x4d544d45 /* "MTME" */
 #define MTIMES_VERSION 1
 
index 272e8d451739e8466a35df155520c9c54d85e75c..1b8052bececc1f9b0a2ef53f04d70334c1b57314 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "object.h"
 #include "pack.h"
 #include "pack-objects.h"
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 08dc1601679f1011f7ff38b7a721dbb4dd116c85..7fffcad9125610cb05a5823b03b86d3e28eeabdb 100644 (file)
@@ -1,9 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
 #include "pack-revindex.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "packfile.h"
+#include "strbuf.h"
+#include "trace2.h"
 #include "config.h"
 #include "midx.h"
+#include "csum-file.h"
 
 struct revindex_entry {
        off_t offset;
@@ -204,10 +209,14 @@ static int load_revindex_from_disk(char *revindex_name,
        size_t revindex_size;
        struct revindex_header *hdr;
 
+       if (git_env_bool(GIT_TEST_REV_INDEX_DIE_ON_DISK, 0))
+               die("dying as requested by '%s'", GIT_TEST_REV_INDEX_DIE_ON_DISK);
+
        fd = git_open(revindex_name);
 
        if (fd < 0) {
-               ret = -1;
+               /* "No file" means return 1. */
+               ret = 1;
                goto cleanup;
        }
        if (fstat(fd, &st)) {
@@ -259,7 +268,7 @@ cleanup:
        return ret;
 }
 
-static int load_pack_revindex_from_disk(struct packed_git *p)
+int load_pack_revindex_from_disk(struct packed_git *p)
 {
        char *revindex_name;
        int ret;
@@ -282,18 +291,58 @@ cleanup:
        return ret;
 }
 
-int load_pack_revindex(struct packed_git *p)
+int load_pack_revindex(struct repository *r, struct packed_git *p)
 {
        if (p->revindex || p->revindex_data)
                return 0;
 
-       if (!load_pack_revindex_from_disk(p))
+       prepare_repo_settings(r);
+
+       if (r->settings.pack_read_reverse_index &&
+           !load_pack_revindex_from_disk(p))
                return 0;
        else if (!create_pack_revindex_in_memory(p))
                return 0;
        return -1;
 }
 
+/*
+ * verify_pack_revindex verifies that the on-disk rev-index for the given
+ * pack-file is the same that would be created if written from scratch.
+ *
+ * A negative number is returned on error.
+ */
+int verify_pack_revindex(struct packed_git *p)
+{
+       int res = 0;
+
+       /* Do not bother checking if not initialized. */
+       if (!p->revindex_map || !p->revindex_data)
+               return res;
+
+       if (!hashfile_checksum_valid((const unsigned char *)p->revindex_map, p->revindex_size)) {
+               error(_("invalid checksum"));
+               res = -1;
+       }
+
+       /* This may fail due to a broken .idx. */
+       if (create_pack_revindex_in_memory(p))
+               return res;
+
+       for (size_t i = 0; i < p->num_objects; i++) {
+               uint32_t nr = p->revindex[i].nr;
+               uint32_t rev_val = get_be32(p->revindex_data + i);
+
+               if (nr != rev_val) {
+                       error(_("invalid rev-index position at %"PRIu64": %"PRIu32" != %"PRIu32""),
+                             (uint64_t)i, nr, rev_val);
+                       res = -1;
+               }
+       }
+
+       return res;
+}
+
 int load_midx_revindex(struct multi_pack_index *m)
 {
        struct strbuf revindex_name = STRBUF_INIT;
@@ -355,7 +404,7 @@ int offset_to_pack_pos(struct packed_git *p, off_t ofs, uint32_t *pos)
 {
        unsigned lo, hi;
 
-       if (load_pack_revindex(p) < 0)
+       if (load_pack_revindex(the_repository, p) < 0)
                return -1;
 
        lo = 0;
index 4974e75eb4d0e9d002fc70a87e5bb4526e1e49f7..6dd47efea10ec69a3438f0a804a71bf13cd91c37 100644 (file)
 #define RIDX_SIGNATURE 0x52494458 /* "RIDX" */
 #define RIDX_VERSION 1
 
-#define GIT_TEST_WRITE_REV_INDEX "GIT_TEST_WRITE_REV_INDEX"
+#define GIT_TEST_NO_WRITE_REV_INDEX "GIT_TEST_NO_WRITE_REV_INDEX"
 #define GIT_TEST_REV_INDEX_DIE_IN_MEMORY "GIT_TEST_REV_INDEX_DIE_IN_MEMORY"
+#define GIT_TEST_REV_INDEX_DIE_ON_DISK "GIT_TEST_REV_INDEX_DIE_ON_DISK"
 
 struct packed_git;
 struct multi_pack_index;
+struct repository;
 
 /*
  * load_pack_revindex populates the revindex's internal data-structures for the
@@ -47,7 +49,23 @@ struct multi_pack_index;
  * If a '.rev' file is present it is mmap'd, and pointers are assigned into it
  * (instead of using the in-memory variant).
  */
-int load_pack_revindex(struct packed_git *p);
+int load_pack_revindex(struct repository *r, struct packed_git *p);
+
+/*
+ * Specifically load a pack revindex from disk.
+ *
+ * Returns 0 on success, 1 on "no .rev file", and -1 when there is an
+ * error parsing the .rev file.
+ */
+int load_pack_revindex_from_disk(struct packed_git *p);
+
+/*
+ * verify_pack_revindex verifies that the on-disk rev-index for the given
+ * pack-file is the same that would be created if written from scratch.
+ *
+ * A negative number is returned on error.
+ */
+int verify_pack_revindex(struct packed_git *p);
 
 /*
  * load_midx_revindex loads the '.rev' file corresponding to the given
index 336372974872882a235598d254c876e31c49b24a..b19ddf15b284868acd7ad9123aed8fba10d08d30 100644 (file)
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "pack.h"
 #include "csum-file.h"
 #include "remote.h"
@@ -6,6 +9,9 @@
 #include "pack-mtimes.h"
 #include "oidmap.h"
 #include "pack-objects.h"
+#include "pack-revindex.h"
+#include "path.h"
+#include "strbuf.h"
 
 void reset_pack_idx_option(struct pack_idx_option *opts)
 {
@@ -309,13 +315,13 @@ static void write_mtimes_trailer(struct hashfile *f, const unsigned char *hash)
        hashwrite(f, hash, the_hash_algo->rawsz);
 }
 
-static const char *write_mtimes_file(struct packing_data *to_pack,
-                                    struct pack_idx_entry **objects,
-                                    uint32_t nr_objects,
-                                    const unsigned char *hash)
+static char *write_mtimes_file(struct packing_data *to_pack,
+                              struct pack_idx_entry **objects,
+                              uint32_t nr_objects,
+                              const unsigned char *hash)
 {
        struct strbuf tmp_file = STRBUF_INIT;
-       const char *mtimes_name;
+       char *mtimes_name;
        struct hashfile *f;
        int fd;
 
@@ -541,7 +547,7 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
                         char **idx_tmp_name)
 {
        const char *rev_tmp_name = NULL;
-       const char *mtimes_tmp_name = NULL;
+       char *mtimes_tmp_name = NULL;
 
        if (adjust_shared_perm(pack_tmp_name))
                die_errno("unable to make temporary pack file readable");
@@ -565,6 +571,9 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
                rename_tmp_packfile(name_buffer, rev_tmp_name, "rev");
        if (mtimes_tmp_name)
                rename_tmp_packfile(name_buffer, mtimes_tmp_name, "mtimes");
+
+       free((char *)rev_tmp_name);
+       free(mtimes_tmp_name);
 }
 
 void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought)
diff --git a/pack.h b/pack.h
index 01d385903adcba22f46633aec3f7c2fff78776f3..3ab9e3f60c0b0341c3cb37e9026bdc217ba6aa97 100644 (file)
--- a/pack.h
+++ b/pack.h
@@ -4,6 +4,8 @@
 #include "object.h"
 #include "csum-file.h"
 
+struct packed_git;
+struct pack_window;
 struct repository;
 
 /*
index 79e21ab18e7844461c3743e45ebb7ccc1022caea..9cc0a2e37a83dd38c2fe1b26d34cfb5fea983bc7 100644 (file)
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "list.h"
 #include "pack.h"
 #include "repository.h"
 #include "commit.h"
 #include "object.h"
 #include "tag.h"
+#include "trace.h"
 #include "tree-walk.h"
 #include "tree.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "midx.h"
 #include "commit-graph.h"
+#include "pack-revindex.h"
 #include "promisor-remote.h"
 
 char *odb_pack_name(struct strbuf *buf,
@@ -178,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;
@@ -373,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;
@@ -745,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;
 }
@@ -1008,6 +1014,16 @@ void reprepare_packed_git(struct repository *r)
        struct object_directory *odb;
 
        obj_read_lock();
+
+       /*
+        * Reprepare alt odbs, in case the alternates file was modified
+        * during the course of this process. This only _adds_ odbs to
+        * the linked list, so existing odbs will continue to exist for
+        * the lifetime of the process.
+        */
+       r->objects->loaded_alternates = 0;
+       prepare_alt_odb(r);
+
        for (odb = r->objects->odb; odb; odb = odb->next)
                odb_clear_loose_cache(odb);
 
@@ -1902,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;
 }
@@ -1930,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);
        }
@@ -2136,7 +2153,7 @@ int for_each_object_in_pack(struct packed_git *p,
        int r = 0;
 
        if (flags & FOR_EACH_OBJECT_PACK_ORDER) {
-               if (load_pack_revindex(p))
+               if (load_pack_revindex(the_repository, p))
                        return -1;
        }
 
@@ -2204,8 +2221,8 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
 }
 
 static int add_promisor_object(const struct object_id *oid,
-                              struct packed_git *pack,
-                              uint32_t pos,
+                              struct packed_git *pack UNUSED,
+                              uint32_t pos UNUSED,
                               void *set_)
 {
        struct oidset *set = set_;
@@ -2263,7 +2280,7 @@ int is_promisor_object(const struct object_id *oid)
        static int promisor_objects_prepared;
 
        if (!promisor_objects_prepared) {
-               if (has_promisor_remote()) {
+               if (repo_has_promisor_remote(the_repository)) {
                        for_each_packed_object(add_promisor_object,
                                               &promisor_objects,
                                               FOR_EACH_OBJECT_PROMISOR_ONLY |
index a3f6723857bf120f611e4f506e85428132f7ccc3..c3692308b8dc866b2b99b2ed9b983db4d6d1352b 100644 (file)
@@ -1,13 +1,27 @@
 #ifndef PACKFILE_H
 #define PACKFILE_H
 
-#include "cache.h"
+#include "object.h"
 #include "oidset.h"
 
 /* in object-store.h */
 struct packed_git;
 struct object_info;
 
+struct pack_window {
+       struct pack_window *next;
+       unsigned char *base;
+       off_t offset;
+       size_t len;
+       unsigned int last_used;
+       unsigned int inuse_cnt;
+};
+
+struct pack_entry {
+       off_t offset;
+       struct packed_git *p;
+};
+
 /*
  * Generate the filename to be used for a pack file with checksum "sha1" and
  * extension "ext". The result is written into the strbuf "buf", overwriting
@@ -65,7 +79,6 @@ struct packed_git *get_all_packs(struct repository *r);
  * for speed.
  */
 unsigned long repo_approximate_object_count(struct repository *r);
-#define approximate_object_count() repo_approximate_object_count(the_repository)
 
 struct packed_git *find_sha1_pack(const unsigned char *sha1,
                                  struct packed_git *packs);
diff --git a/pager.c b/pager.c
index b66bbff2785cb6ed032edb4f0d9cd68f6a841c36..b8822a9381e49487ecb9bf37f1a42f1414eb8ff3 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -1,9 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "editor.h"
+#include "pager.h"
 #include "run-command.h"
 #include "sigchain.h"
 #include "alias.h"
 
+int pager_use_color = 1;
+
 #ifndef DEFAULT_PAGER
 #define DEFAULT_PAGER "less"
 #endif
@@ -39,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"))
@@ -224,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;
diff --git a/pager.h b/pager.h
new file mode 100644 (file)
index 0000000..b774330
--- /dev/null
+++ b/pager.h
@@ -0,0 +1,17 @@
+#ifndef PAGER_H
+#define PAGER_H
+
+struct child_process;
+
+const char *git_pager(int stdout_is_tty);
+void setup_pager(void);
+int pager_in_use(void);
+int term_columns(void);
+void term_clear_line(void);
+int decimal_width(uintmax_t);
+int check_pager_config(const char *cmd);
+void prepare_pager_args(struct child_process *, const char *pager);
+
+extern int pager_use_color;
+
+#endif /* PAGER_H */
index 4f6819f2406ea8f90651b7769cbaf1758ce4c098..b5a714c7111bda0d179077ef1614bbe5ce1570b5 100644 (file)
@@ -1,12 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "entry.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #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"
 
index d346dbe2100ddceb53f8ce149ad4ed794b772f53..a24521dee0fca3de6284a9c59cd3bd8cefdb4942 100644 (file)
@@ -1,9 +1,12 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
 #include "branch.h"
-#include "cache.h"
 #include "commit.h"
 #include "color.h"
+#include "date.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
 #include "string-list.h"
 #include "strvec.h"
 #include "oid-array.h"
@@ -91,7 +94,7 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset)
 
        if (!arg)
                return -1;
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                return error("malformed object name %s", arg);
        commit = lookup_commit_reference(the_repository, &oid);
        if (!commit)
@@ -110,7 +113,7 @@ int parse_opt_commit(const struct option *opt, const char *arg, int unset)
 
        if (!arg)
                return -1;
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                return error("malformed object name %s", arg);
        commit = lookup_commit_reference(the_repository, &oid);
        if (!commit)
@@ -129,7 +132,7 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset)
        }
        if (!arg)
                return -1;
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                return error(_("malformed object name '%s'"), arg);
        oid_array_append(opt->value, &oid);
        return 0;
@@ -146,7 +149,7 @@ int parse_opt_object_id(const struct option *opt, const char *arg, int unset)
        }
        if (!arg)
                return -1;
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                return error(_("malformed object name '%s'"), arg);
        *target = oid;
        return 0;
@@ -208,24 +211,25 @@ int parse_opt_string_list(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_strvec(const struct option *opt, const char *arg, int unset)
 {
+       struct strvec *v = opt->value;
+
+       if (unset) {
+               strvec_clear(v);
+               return 0;
+       }
+
+       if (!arg)
+               return -1;
+
+       strvec_push(v, arg);
        return 0;
 }
 
-/**
- * Report that the option is unknown, so that other code can handle
- * it. This can be used as a callback together with
- * OPTION_LOWLEVEL_CALLBACK to allow an option to be documented in the
- * "-h" output even if it's not being handled directly by
- * parse_options().
- */
-enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx,
-                                          const struct option *opt,
-                                          const char *arg, int unset)
+int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
 {
-       BUG_ON_OPT_ARG(arg);
-       return PARSE_OPT_UNKNOWN;
+       return 0;
 }
 
 /**
index fd4743293fc48f9453499ad4f9695462b9c08217..60224cf8d03fb1764ad26da422f7158898b631ea 100644 (file)
@@ -1,9 +1,11 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
-#include "cache.h"
+#include "abspath.h"
 #include "config.h"
 #include "commit.h"
 #include "color.h"
+#include "gettext.h"
+#include "strbuf.h"
 #include "utf8.h"
 
 static int disallow_abbreviated_options;
@@ -59,12 +61,12 @@ static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p,
        return 0;
 }
 
-static void fix_filename(const char *prefix, const char **file)
+static void fix_filename(const char *prefix, char **file)
 {
-       if (!file || !*file || !prefix || is_absolute_path(*file)
-           || !strcmp("-", *file))
-               return;
-       *file = prefix_filename(prefix, *file);
+       if (!file || !*file)
+               ; /* leave as NULL */
+       else
+               *file = prefix_filename_except_for_dash(prefix, *file);
 }
 
 static enum parse_opt_result opt_command_mode_error(
@@ -177,7 +179,7 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
                        err = get_arg(p, opt, flags, (const char **)opt->value);
 
                if (!err)
-                       fix_filename(p->prefix, (const char **)opt->value);
+                       fix_filename(p->prefix, (char **)opt->value);
                return err;
 
        case OPTION_CALLBACK:
@@ -478,6 +480,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:
@@ -1107,6 +1112,7 @@ 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;
 
                if (opts->type == OPTION_SUBCOMMAND)
                        continue;
@@ -1143,7 +1149,9 @@ 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)
+               if (pos == USAGE_OPTS_WIDTH + 1)
+                       pad = -1;
+               else if (pos <= USAGE_OPTS_WIDTH)
                        pad = USAGE_OPTS_WIDTH - pos;
                else {
                        fputc('\n', outfile);
@@ -1155,7 +1163,16 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
                                   (const char *)opts->value);
                        continue;
                }
-               fprintf(outfile, "%*s%s\n", pad + USAGE_GAP, "", _(opts->help));
+
+               for (cp = _(opts->help); *cp; cp = np) {
+                       np = strchrnul(cp, '\n');
+                       fprintf(outfile,
+                               "%*s%.*s\n", pad + USAGE_GAP, "",
+                               (int)(np - cp), cp);
+                       if (*np)
+                               np++;
+                       pad = USAGE_OPTS_WIDTH;
+               }
        }
        fputc('\n', outfile);
 
index 50d852f2991738c951bb447ce8206640aabb8a80..57a7fe9d91a1690e59e05838897a8d474aca5de1 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef PARSE_OPTIONS_H
 #define PARSE_OPTIONS_H
 
+#include "gettext.h"
+
 /**
  * Refer to Documentation/technical/api-parse-options.txt for the API doc.
  */
@@ -158,71 +160,211 @@ struct option {
        parse_opt_subcommand_fn *subcommand_fn;
 };
 
-#define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
-                                     PARSE_OPT_NOARG|(f), NULL, (b) }
-#define OPT_COUNTUP_F(s, l, v, h, f) { OPTION_COUNTUP, (s), (l), (v), NULL, \
-                                      (h), PARSE_OPT_NOARG|(f) }
-#define OPT_SET_INT_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
-                                         (h), PARSE_OPT_NOARG | (f), NULL, (i) }
+#define OPT_BIT_F(s, l, v, h, b, f) { \
+       .type = OPTION_BIT, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG|(f), \
+       .callback = NULL, \
+       .defval = (b), \
+}
+#define OPT_COUNTUP_F(s, l, v, h, f) { \
+       .type = OPTION_COUNTUP, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG|(f), \
+}
+#define OPT_SET_INT_F(s, l, v, h, i, f) { \
+       .type = OPTION_SET_INT, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG | (f), \
+       .defval = (i), \
+}
 #define OPT_BOOL_F(s, l, v, h, f)   OPT_SET_INT_F(s, l, v, h, 1, f)
-#define OPT_CALLBACK_F(s, l, v, a, h, f, cb)                   \
-       { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), (cb) }
-#define OPT_STRING_F(s, l, v, a, h, f)   { OPTION_STRING,  (s), (l), (v), (a), (h), (f) }
-#define OPT_INTEGER_F(s, l, v, h, f)     { OPTION_INTEGER, (s), (l), (v), N_("n"), (h), (f) }
+#define OPT_CALLBACK_F(s, l, v, a, h, f, cb) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = (a), \
+       .help = (h), \
+       .flags = (f), \
+       .callback = (cb), \
+}
+#define OPT_STRING_F(s, l, v, a, h, f) { \
+       .type = OPTION_STRING, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = (a), \
+       .help = (h), \
+       .flags = (f), \
+}
+#define OPT_INTEGER_F(s, l, v, h, f) { \
+       .type = OPTION_INTEGER, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("n"), \
+       .help = (h), \
+       .flags = (f), \
+}
 
-#define OPT_END()                   { OPTION_END }
-#define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
+#define OPT_END() { \
+       .type = OPTION_END, \
+}
+#define OPT_GROUP(h) { \
+       .type = OPTION_GROUP, \
+       .help = (h), \
+}
 #define OPT_BIT(s, l, v, h, b)      OPT_BIT_F(s, l, v, h, b, 0)
-#define OPT_BITOP(s, l, v, h, set, clear) { OPTION_BITOP, (s), (l), (v), NULL, (h), \
-                                           PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, \
-                                           (set), NULL, (clear) }
-#define OPT_NEGBIT(s, l, v, h, b)   { OPTION_NEGBIT, (s), (l), (v), NULL, \
-                                     (h), PARSE_OPT_NOARG, NULL, (b) }
+#define OPT_BITOP(s, l, v, h, set, clear) { \
+       .type = OPTION_BITOP, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG|PARSE_OPT_NONEG, \
+       .defval = (set), \
+       .extra = (clear), \
+}
+#define OPT_NEGBIT(s, l, v, h, b) { \
+       .type = OPTION_NEGBIT, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG, \
+       .defval = (b), \
+}
 #define OPT_COUNTUP(s, l, v, h)     OPT_COUNTUP_F(s, l, v, h, 0)
 #define OPT_SET_INT(s, l, v, h, i)  OPT_SET_INT_F(s, l, v, h, i, 0)
 #define OPT_BOOL(s, l, v, h)        OPT_BOOL_F(s, l, v, h, 0)
-#define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
-                                     (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
-#define OPT_CMDMODE_F(s, l, v, h, i, f)  { OPTION_SET_INT, (s), (l), (v), NULL, \
-                                     (h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), NULL, (i) }
+#define OPT_HIDDEN_BOOL(s, l, v, h) { \
+       .type = OPTION_SET_INT, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, \
+       .defval = 1, \
+}
+#define OPT_CMDMODE_F(s, l, v, h, i, f) { \
+       .type = OPTION_SET_INT, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), \
+       .defval = (i), \
+}
 #define OPT_CMDMODE(s, l, v, h, i)  OPT_CMDMODE_F(s, l, v, h, i, 0)
 
 #define OPT_INTEGER(s, l, v, h)     OPT_INTEGER_F(s, l, v, h, 0)
-#define OPT_MAGNITUDE(s, l, v, h)   { OPTION_MAGNITUDE, (s), (l), (v), \
-                                     N_("n"), (h), PARSE_OPT_NONEG }
+#define OPT_MAGNITUDE(s, l, v, h) { \
+       .type = OPTION_MAGNITUDE, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("n"), \
+       .help = (h), \
+       .flags = PARSE_OPT_NONEG, \
+}
 #define OPT_STRING(s, l, v, a, h)   OPT_STRING_F(s, l, v, a, h, 0)
-#define OPT_STRING_LIST(s, l, v, a, h) \
-                                   { OPTION_CALLBACK, (s), (l), (v), (a), \
-                                     (h), 0, &parse_opt_string_list }
-#define OPT_UYN(s, l, v, h)         { OPTION_CALLBACK, (s), (l), (v), NULL, \
-                                     (h), PARSE_OPT_NOARG, &parse_opt_tertiary }
-#define OPT_EXPIRY_DATE(s, l, v, h) \
-       { OPTION_CALLBACK, (s), (l), (v), N_("expiry-date"),(h), 0,     \
-         parse_opt_expiry_date_cb }
-#define OPT_CALLBACK(s, l, v, a, h, f) OPT_CALLBACK_F(s, l, v, a, h, 0, f)
-#define OPT_NUMBER_CALLBACK(v, h, f) \
-       { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
-         PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
-#define OPT_FILENAME(s, l, v, h)    { OPTION_FILENAME, (s), (l), (v), \
-                                      N_("file"), (h) }
-#define OPT_COLOR_FLAG(s, l, v, h) \
-       { OPTION_CALLBACK, (s), (l), (v), N_("when"), (h), PARSE_OPT_OPTARG, \
-               parse_opt_color_flag_cb, (intptr_t)"always" }
-
-#define OPT_NOOP_NOARG(s, l) \
-       { OPTION_CALLBACK, (s), (l), NULL, NULL, \
-         N_("no-op (backward compatibility)"),         \
-         PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
-
-#define OPT_ALIAS(s, l, source_long_name) \
-       { OPTION_ALIAS, (s), (l), (source_long_name) }
+#define OPT_STRING_LIST(s, l, v, a, h) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = (a), \
+       .help = (h), \
+       .callback = &parse_opt_string_list, \
+}
+#define OPT_STRVEC(s, l, v, a, h) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = (a), \
+       .help = (h), \
+       .callback = &parse_opt_strvec, \
+}
+#define OPT_UYN(s, l, v, h) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG, \
+       .callback = &parse_opt_tertiary, \
+}
+#define OPT_EXPIRY_DATE(s, l, v, h) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("expiry-date"), \
+       .help = (h), \
+       .callback = parse_opt_expiry_date_cb, \
+}
+#define OPT_CALLBACK(s, l, v, a, h, cb) OPT_CALLBACK_F(s, l, v, a, h, 0, cb)
+#define OPT_NUMBER_CALLBACK(v, h, cb) { \
+       .type = OPTION_NUMBER, \
+       .value = (v), \
+       .help = (h), \
+       .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, \
+       .callback = (cb), \
+}
+#define OPT_FILENAME(s, l, v, h) { \
+       .type = OPTION_FILENAME, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("file"), \
+       .help = (h), \
+}
+#define OPT_COLOR_FLAG(s, l, v, h) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("when"), \
+       .help = (h), \
+       .flags = PARSE_OPT_OPTARG, \
+       .callback = parse_opt_color_flag_cb, \
+       .defval = (intptr_t)"always", \
+}
+
+#define OPT_NOOP_NOARG(s, l) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .help = N_("no-op (backward compatibility)"), \
+       .flags = PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, \
+       .callback = parse_opt_noop_cb, \
+}
+
+#define OPT_ALIAS(s, l, source_long_name) { \
+       .type = OPTION_ALIAS, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (source_long_name), \
+}
 
 #define OPT_SUBCOMMAND_F(l, v, fn, f) { \
        .type = OPTION_SUBCOMMAND, \
        .long_name = (l), \
        .value = (v), \
        .flags = (f), \
-       .subcommand_fn = (fn) }
+       .subcommand_fn = (fn), \
+}
 #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)
 
 /*
@@ -347,10 +489,8 @@ int parse_opt_commits(const struct option *, const char *, int);
 int parse_opt_commit(const struct option *, const char *, int);
 int parse_opt_tertiary(const struct option *, const char *, int);
 int parse_opt_string_list(const struct option *, const char *, int);
+int parse_opt_strvec(const struct option *, const char *, int);
 int parse_opt_noop_cb(const struct option *, const char *, int);
-enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx,
-                                          const struct option *,
-                                          const char *, int);
 int parse_opt_passthru(const struct option *, const char *, int);
 int parse_opt_passthru_argv(const struct option *, const char *, int);
 /* value is enum branch_track* */
@@ -358,34 +498,80 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
 
 #define OPT__VERBOSE(var, h)  OPT_COUNTUP('v', "verbose", (var), (h))
 #define OPT__QUIET(var, h)    OPT_COUNTUP('q', "quiet",   (var), (h))
-#define OPT__VERBOSITY(var) \
-       { OPTION_CALLBACK, 'v', "verbose", (var), NULL, N_("be more verbose"), \
-         PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
-       { OPTION_CALLBACK, 'q', "quiet", (var), NULL, N_("be more quiet"), \
-         PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
+#define OPT__VERBOSITY(var) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = 'v', \
+       .long_name = "verbose", \
+       .value = (var), \
+       .help = N_("be more verbose"), \
+       .flags = PARSE_OPT_NOARG, \
+       .callback = &parse_opt_verbosity_cb, \
+}, { \
+       .type = OPTION_CALLBACK, \
+       .short_name = 'q', \
+       .long_name = "quiet", \
+       .value = (var), \
+       .help = N_("be more quiet"), \
+       .flags = PARSE_OPT_NOARG, \
+       .callback = &parse_opt_verbosity_cb, \
+}
 #define OPT__DRY_RUN(var, h)  OPT_BOOL('n', "dry-run", (var), (h))
 #define OPT__FORCE(var, h, f) OPT_COUNTUP_F('f', "force",   (var), (h), (f))
-#define OPT__ABBREV(var)  \
-       { OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
-         N_("use <n> digits to display object names"), \
-         PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__ABBREV(var) { \
+       .type = OPTION_CALLBACK, \
+       .long_name = "abbrev", \
+       .value = (var), \
+       .argh = N_("n"), \
+       .help = N_("use <n> digits to display object names"), \
+       .flags = PARSE_OPT_OPTARG, \
+       .callback = &parse_opt_abbrev_cb, \
+}
 #define OPT__SUPER_PREFIX(var) \
        OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
                N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
 
 #define OPT__COLOR(var, h) \
        OPT_COLOR_FLAG(0, "color", (var), (h))
-#define OPT_COLUMN(s, l, v, h) \
-       { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
-#define OPT_PASSTHRU(s, l, v, a, h, f) \
-       { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), parse_opt_passthru }
-#define OPT_PASSTHRU_ARGV(s, l, v, a, h, f) \
-       { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), parse_opt_passthru_argv }
-#define _OPT_CONTAINS_OR_WITH(name, variable, help, flag) \
-       { OPTION_CALLBACK, 0, name, (variable), N_("commit"), (help), \
-         PARSE_OPT_LASTARG_DEFAULT | flag, \
-         parse_opt_commits, (intptr_t) "HEAD" \
-       }
+#define OPT_COLUMN(s, l, v, h) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("style"), \
+       .help = (h), \
+       .flags = PARSE_OPT_OPTARG, \
+       .callback = parseopt_column_callback, \
+}
+#define OPT_PASSTHRU(s, l, v, a, h, f) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = (a), \
+       .help = (h), \
+       .flags = (f), \
+       .callback = parse_opt_passthru, \
+}
+#define OPT_PASSTHRU_ARGV(s, l, v, a, h, f) { \
+       .type = OPTION_CALLBACK, \
+       .short_name = (s), \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = (a), \
+       .help = (h), \
+       .flags = (f), \
+       .callback = parse_opt_passthru_argv, \
+}
+#define _OPT_CONTAINS_OR_WITH(l, v, h, f) { \
+       .type = OPTION_CALLBACK, \
+       .long_name = (l), \
+       .value = (v), \
+       .argh = N_("commit"), \
+       .help = (h), \
+       .flags = PARSE_OPT_LASTARG_DEFAULT | (f), \
+       .callback = parse_opt_commits, \
+       .defval = (intptr_t) "HEAD", \
+}
 #define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, PARSE_OPT_NONEG)
 #define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
 #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
@@ -395,4 +581,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
index 31534466266ccd80cd02ce187a1a4c799934e056..c3e1a0dd216c80c92c47f0e2a98d74a57c422742 100644 (file)
@@ -1,7 +1,9 @@
-#include "cache.h"
+#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"
 
 static int patch_id_defined(struct commit *commit)
diff --git a/path.c b/path.c
index 492e17ad12106233ddde63b724992f388693be10..67e2690efef897b406d46eab6202b52fc65a55d0 100644 (file)
--- a/path.c
+++ b/path.c
@@ -1,16 +1,21 @@
 /*
  * Utilities for paths and pathnames
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "repository.h"
 #include "strbuf.h"
 #include "string-list.h"
 #include "dir.h"
 #include "worktree.h"
+#include "setup.h"
 #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"
 
@@ -347,7 +352,8 @@ static void init_common_trie(void)
  * Helper function for update_common_dir: returns 1 if the dir
  * prefix is common.
  */
-static int check_common(const char *unmatched, void *value, void *baton)
+static int check_common(const char *unmatched, void *value,
+                       void *baton UNUSED)
 {
        struct common_dir *dir = value;
 
@@ -1206,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 0a59c85a62eda03acd290fa564b7e197288e26ad..639372edd9ee36127e3b89084f89ee59d12ff60f 100644 (file)
--- a/path.h
+++ b/path.h
@@ -3,6 +3,7 @@
 
 struct repository;
 struct strbuf;
+struct string_list;
 
 /*
  * The result to all functions which return statically allocated memory may be
@@ -179,7 +180,71 @@ const char *git_path_auto_merge(struct repository *r);
 const char *git_path_fetch_head(struct repository *r);
 const char *git_path_shallow(struct repository *r);
 
-
 int ends_with_path_components(const char *path, const char *components);
+int validate_headref(const char *ref);
+
+int adjust_shared_perm(const char *path);
+
+char *interpolate_path(const char *path, int real_home);
+const char *enter_repo(const char *path, int strict);
+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);
+
+/*
+ * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
+ * details.
+ */
+int is_ntfs_dotgit(const char *name);
+int is_ntfs_dotgitmodules(const char *name);
+int is_ntfs_dotgitignore(const char *name);
+int is_ntfs_dotgitattributes(const char *name);
+int is_ntfs_dotmailmap(const char *name);
+
+/*
+ * Returns true iff "str" could be confused as a command-line option when
+ * passed to a sub-program like "ssh". Note that this has nothing to do with
+ * shell-quoting, which should be handled separately; we're assuming here that
+ * the string makes it verbatim to the sub-program.
+ */
+int looks_like_command_line_option(const char *str);
+
+/**
+ * Return a newly allocated string with the evaluation of
+ * "$XDG_CONFIG_HOME/$subdir/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
+ * "$HOME/.config/$subdir/$filename". Return NULL upon error.
+ */
+char *xdg_config_home_for(const char *subdir, const char *filename);
+
+/**
+ * Return a newly allocated string with the evaluation of
+ * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
+ * "$HOME/.config/git/$filename". Return NULL upon error.
+ */
+char *xdg_config_home(const char *filename);
+
+/**
+ * Return a newly allocated string with the evaluation of
+ * "$XDG_CACHE_HOME/git/$filename" if $XDG_CACHE_HOME is non-empty, otherwise
+ * "$HOME/.cache/git/$filename". Return NULL upon error.
+ */
+char *xdg_cache_home(const char *filename);
+
+/*
+ * Create a directory and (if share is nonzero) adjust its permissions
+ * according to the shared_repository setting. Only use this for
+ * directories under $GIT_DIR.  Don't use it for working tree
+ * directories.
+ */
+void safe_create_dir(const char *dir, int share);
 
 #endif /* PATH_H */
index ab70fcbe613526dd09e59cb87d2393c95409d28d..3a3a5724c44bcb7b53d10ddce6f0f9f9f397512b 100644 (file)
@@ -1,10 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.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.
@@ -525,24 +533,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
@@ -730,7 +743,7 @@ int match_pathspec_attrs(struct index_state *istate,
        if (name[namelen])
                name = to_free = xmemdupz(name, namelen);
 
-       git_check_attr(istate, NULL, name, item->attr_check);
+       git_check_attr(istate, name, item->attr_check);
 
        free(to_free);
 
index 41f6adfbb421fee745e3717ffd57ff92acfc82b1..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)
 {
@@ -171,6 +179,11 @@ int match_pathspec_attrs(struct index_state *istate,
                         const char *name, int namelen,
                         const struct pathspec_item *item);
 
+int match_pathspec(struct index_state *istate,
+                  const struct pathspec *pathspec,
+                  const char *name, int namelen,
+                  int prefix, char *seen, int is_dir);
+
 /*
  * Determine whether a pathspec will match only entire index entries (non-sparse
  * files and/or entire sparse directories). If the pathspec has the potential to
index ce4e73b6833a48119dfc5f36b64daa8e962dc9c4..af83a19f4df5537da9f1c7a87ea29cb2f5903ea2 100644 (file)
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "copy.h"
 #include "pkt-line.h"
+#include "gettext.h"
+#include "hex.h"
 #include "run-command.h"
+#include "trace.h"
+#include "write-or-die.h"
 
 char packet_buffer[LARGE_PACKET_MAX];
 static const char *packet_trace_prefix = "git";
@@ -367,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)
@@ -413,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 79c538b99e477660fb8819d7fd0175daf4520cc5..954eec87197d3e0c50812879d47e0afbb008baa3 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef PKTLINE_H
 #define PKTLINE_H
 
-#include "git-compat-util.h"
 #include "strbuf.h"
 #include "sideband.h"
 
@@ -95,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
@@ -247,4 +246,6 @@ void packet_writer_error(struct packet_writer *writer, const char *fmt, ...);
 void packet_writer_delim(struct packet_writer *writer);
 void packet_writer_flush(struct packet_writer *writer);
 
+void packet_trace_identity(const char *prog);
+
 #endif
index 5a63397655a271bf5051f53058db864439020b3d..87df7c6962e2b340d3e78ab8135038186dafb560 100644 (file)
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -51,7 +51,7 @@ Repository:   https://github.com/Arusekk/git-po
 Leader:                Arusekk <arek_koz@o2.pl>
 
 Language:      pt_PT (Portuguese - Portugal)
-Repository:    https://codeberg.org/git-pt/Git-PO-pt_PT/
+Repository:    https://gitlab.com/alexandre1985/git-pt/
 Leader:                Daniel Santos <dacs.git@brilhante.top>
 
 Language:      ru (Russian)
@@ -67,16 +67,22 @@ Language:   tr (Turkish)
 Repository:    https://github.com/bitigchi/git-po/
 Leader:                Emir SARI <bitigchi@me.com>
 
+Language:      uk (Ukrainian)
+Repository:    https://github.com/arkid15r/git-ukrainian-l10n/
+Leader:                Arkadii Yakovets <ark@cho.red>
+Members:       Kateryna Golovanova <kate@kgthreads.com>
+
 Language:      vi (Vietnamese)
 Repository:    https://github.com/vnwildman/git/
 Leader:                Trần Ngọc Quân <vnwildman AT gmail.com>
 Members:       Nguyễn Thái Ngọc Duy <pclouds AT gmail.com>
 
 Language:      zh_CN (Simplified Chinese)
-Repository:    https://github.com/fangyi-zhou/git-po/
-Leader:                Fangyi Zhou <me AT fangyi.io>
+Repository:    https://github.com/dyrone/git/
+Leader:                Teng Long <dyroneteng AT gmail.com>
 Members:       Ray Chen <oldsharp AT gmail.com>
                依云 <lilydjwg AT gmail.com>
+               Fangyi Zhou <me AT fangyi.io>
                Jiang Xin <worldhello.net AT gmail.com>
 
 Language:      zh_TW (Traditional Chinese)
index daec1326c06dd1597266c67d01b61b85312f54be..61214c4b1c5eb2a658503a0be9dfaaf23568597c 100644 (file)
--- a/po/bg.po
+++ b/po/bg.po
 # gitattributes file файл с атрибути на git
 # advertised обявен за наличен
 # superproject свръхпроект
-#
+# rev-index обратен индекс (reverse index)
+# dererging branches раздалечили се клони
 # ------------------------
 # „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
 # ------------------------
 # for i in `sort -u FILES`; do cnt=`grep $i FILES | wc -l`; echo $cnt $i ;done | sort -n
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.40\n"
+"Project-Id-Version: git 2.41\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-03-01 01:20+0000\n"
-"PO-Revision-Date: 2023-03-02 08:54+0200\n"
+"POT-Creation-Date: 2023-05-19 19:48+0200\n"
+"PO-Revision-Date: 2023-05-19 20:57+0300\n"
 "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
 "Language-Team: Bulgarian <dict@fsa-bg.org>\n"
 "Language: bg\n"
@@ -890,6 +891,23 @@ 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 ""
+"Раздалечили се клони не може да се превъртят.  Ползвайте:\n"
+"\n"
+"  git merge --no-ff\n"
+"\n"
+"или:\n"
+"\n"
+"  git rebase\n"
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "Не може да се извърши превъртане, преустановяване на действието."
 
@@ -1353,6 +1371,10 @@ msgstr "съкращаване на името на файла с отхвърл
 msgid "cannot open %s"
 msgstr "„%s“ не може да бъде отворен"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "„%s“ не може да се изтрие"
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "%d-то парче бе успешно приложено."
@@ -1546,6 +1568,10 @@ msgstr "git archive --remote ХРАНИЛИЩЕ [--exec КОМАНДА] --list"
 msgid "cannot read '%s'"
 msgstr "файлът „%s“ не може да бъде прочетен"
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "пътят „%s“ съвпада с файлове извън текущата директория"
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "пътят „%s“ не съвпада с никой файл"
@@ -1562,9 +1588,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 "Файлът „%s“ липсва"
@@ -1691,6 +1714,11 @@ msgstr "прескачане на прекалено големия файл з
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "прескачане на прекалено големия обект-BLOB за атрибути на git: „%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"
@@ -1796,9 +1824,6 @@ msgstr[1] "Двоично търсене: остават %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“ изисква "
@@ -1985,10 +2010,6 @@ msgstr "подмодул „%s“: клонът „%s“ не може да се
 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 [ОПЦИЯ…] [--] ПЪТ…"
 
@@ -3080,6 +3101,14 @@ msgstr "Не може да изтриете клона „%s“, който е 
 msgid "remote-tracking branch '%s' not found."
 msgstr "следящият клон „%s“ не може да бъде открит."
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"клонът „%s“ не може да бъде открит.\n"
+"Пробвахте ли опцията „--remote“?"
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "клонът „%s“ не може да бъде открит."
@@ -3110,6 +3139,10 @@ msgstr "Клонът „%s“ се пребазира върху „%s“"
 msgid "Branch %s is being bisected at %s"
 msgstr "Търси се двоично в клона „%s“ при „%s“"
 
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "Указателят „HEAD“ на работното дърво „%s“ не е обновен"
+
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Неправилно име на клон: „%s“"
@@ -3213,6 +3246,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 "копиране на клон и принадлежащия му журнал на указателите"
 
@@ -3436,12 +3472,10 @@ msgid "Created new report at '%s'.\n"
 msgstr "Новият доклад е създаден в „%s“.\n"
 
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress ]\n"
 "                  [--version=ВЕРСИЯ] ФАЙЛ ОПЦИЯ_ЗА_git-rev-list…"
 
 msgid "git bundle verify [-q | --quiet] <file>"
@@ -3462,12 +3496,11 @@ msgstr "без извеждане на напредъка"
 msgid "show progress meter"
 msgstr "извеждане на напредъка"
 
-msgid "show progress meter during object writing phase"
-msgstr "извеждане Ð½Ð° Ð½Ð°Ð¿Ñ\80едÑ\8aка Ð²Ñ\8aв Ñ\84азаÑ\82а Ð½Ð° Ð·Ð°Ð¿Ð°Ð·Ð²Ð°Ð½Ðµ Ð½Ð° Ð¾Ð±ÐµÐºÑ\82иÑ\82е"
+msgid "historical; same as --progress"
+msgstr "изоÑ\81Ñ\82авена Ð¾Ð¿Ñ\86иÑ\8f, Ñ\81Ñ\8aÑ\89оÑ\82о ÐºÐ°Ñ\82о â\80\9e--progressâ\80\9c"
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr ""
-"същото действие като опцията „--all-progress“ при извеждането на напредъка"
+msgid "historical; does nothing"
+msgstr "изоставена опция, нищо не прави"
 
 msgid "specify bundle format version"
 msgstr "версия на пратката"
@@ -4498,6 +4531,10 @@ msgstr "не може да бъде получена информация чре
 msgid "%s exists and is not a directory"
 msgstr "„%s“ съществува и не е директория"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "„%s“ е символна връзка, не може да се клонира с опцията „--local“"
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "неуспешно итериране по „%s“"
@@ -6071,118 +6108,13 @@ msgstr "git fetch --all [ОПЦИЯ…]"
 msgid "fetch.parallel cannot be negative"
 msgstr "опцията „fetch.parallel“ трябва да е неотрицателна"
 
-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 ""
-"промяна на указателя, така че и той, както останалите, да бъде в „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 "ПРИ НУЖДА"
-
-msgid "control recursive fetching of submodules"
-msgstr "управление на рекурсивното доставяне на подмодулите"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "запазване на доставените указатели във файла „FETCH_HEAD“"
-
-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 "изпълняване на „maintenance --auto“ след доставяне"
-
-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 "указателят „HEAD“ в отдалеченото хранилище не може да бъде открит"
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "От %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "обектът „%s“ липсва"
@@ -6258,10 +6190,6 @@ msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr ""
 "отхвърляне на „%s“, защото плитките върхове не може да бъдат обновявани"
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "От %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -6355,6 +6283,115 @@ msgstr ""
 msgid "you need to specify a tag name"
 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 ""
+"промяна на указателя, така че и той, както останалите, да бъде в „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 "ПРИ НУЖДА"
+
+msgid "control recursive fetching of submodules"
+msgstr "управление на рекурсивното доставяне на подмодулите"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "запазване на доставените указатели във файла „FETCH_HEAD“"
+
+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 "изпълняване на „maintenance --auto“ след доставяне"
+
+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 ""
 "Опцията „--negotiate-only“ изисква една или повече опции „--negotiation-"
@@ -6473,6 +6510,12 @@ msgstr "извеждане само на указателите, които съ
 msgid "print only refs which don't contain the commit"
 msgstr "извеждане само на указателите, които не съдържат това ПОДАВАНЕ"
 
+msgid "read reference patterns from stdin"
+msgstr "изчитане на шаблоните за указатели от стандартния вход"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "непознат аргумент към опцията „--stdin“"
+
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=НАСТРОЙКА [--] АРГУМЕНТ…"
 
@@ -6485,6 +6528,10 @@ msgstr "настройка, която съдържа списък с пътищ
 msgid "missing --config=<config>"
 msgstr "липсва --config=НАСТРОЙКА"
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "получена е неправилена настройка „--config=%s“"
+
 msgid "unknown"
 msgstr "непознат"
 
@@ -6631,19 +6678,28 @@ msgstr "%s: несвързаният връх „HEAD“ не сочи към н
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "предупреждение: „%s“ сочи към все още несъществуващ клон (%s)"
 
-msgid "Checking cache tree"
-msgstr "Проверка на кеша на обектите-дървета"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Проверка на кеша на обектите-дървета на „%s“"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "„%s“: неправилен указател за SHA1 в кеша на обектите-дървета"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "„%s“: неправилен указател за SHA1 в кеша на обектите-дървета на „%s“"
 
 msgid "non-tree in cache-tree"
 msgstr "в кеша на обектите-дървета има нещо, което не е дърво"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "„%s“: неправилен указател за отмяна на разрешените подавания"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "„%s“: неправилен указател за отмяна на разрешените подавания на „%s“"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "обратният индекс на пакета „%s“ не може да бъде зареден"
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "неправилен обратен индекс за пакета „%s“"
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -9584,6 +9640,13 @@ 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 "ВЕРСИЯ[,ОТМЕСТВАНЕ]"
 
@@ -9788,6 +9851,9 @@ msgstr ""
 "ни известите с е-писмо до пощенския списък:\n"
 "<git@vger.kernel.org>.\n"
 
+msgid "refusing to run without --i-still-use-this"
+msgstr "трябва да добавите и опцията „--i-still-use-this“"
+
 msgid "git pack-refs [--all] [--no-prune]"
 msgstr "git pack-refs [--all] [--no-prune]"
 
@@ -9962,8 +10028,8 @@ msgstr "Обновяване на все още несъздаден клон с
 msgid "pull with rebase"
 msgstr "издърпване с пребазиране"
 
-msgid "please commit or stash them."
-msgstr "трябва да подадете или скатаете промѐните."
+msgid "Please commit or stash them."
+msgstr "Промѐните трябва или да се подадат, или да се скатаят."
 
 #, c-format
 msgid ""
@@ -10001,7 +10067,7 @@ msgstr "Не може да превъртите към повече от еди
 
 msgid "Need to specify how to reconcile divergent branches."
 msgstr ""
-"ТÑ\80Ñ\8fбва Ð´Ð° Ñ\83кажеÑ\82е ÐºÐ°Ðº Ð´Ð° Ñ\81е Ñ\80еÑ\88аваÑ\82 Ñ\80азликиÑ\82е Ð¿Ñ\80и Ñ\80азминаване на клоните."
+"ТÑ\80Ñ\8fбва Ð´Ð° Ñ\83кажеÑ\82е ÐºÐ°Ðº Ð´Ð° Ñ\81е Ñ\80еÑ\88аваÑ\82 Ñ\80азликиÑ\82е Ð¿Ñ\80и Ñ\80аздалеÑ\87аване на клоните."
 
 msgid "cannot rebase with locally recorded submodule modifications"
 msgstr ""
@@ -10210,8 +10276,8 @@ msgstr "Неправилна стойност за „%s“"
 msgid "repository"
 msgstr "хранилище"
 
-msgid "push all refs"
-msgstr "изтласкване на всички указатели"
+msgid "push all branches"
+msgstr "изтласкване на всички клони"
 
 msgid "mirror all refs"
 msgstr "огледално копие на всички указатели"
@@ -10219,8 +10285,10 @@ 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 ""
+"изтласкване на етикетите (несъвместимо с опциите „--all“, „--branches“ и „--"
+"mirror“)"
 
 msgid "force updates"
 msgstr "принудително обновяване"
@@ -10484,6 +10552,10 @@ msgstr ""
 "\n"
 "В резултат те не може да се пребазират."
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Неправилен режим за „--rebase-merges“: %s"
+
 #, c-format
 msgid "could not switch to %s"
 msgstr "не може да се премине към „%s“"
@@ -10499,6 +10571,15 @@ 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“ с празен низ за аргумент е остаряло и в "
+"бъдеще ще спре да работи. Ползвайте опцията „--rebase-merges“ без аргумент, "
+"за да постигнете същия резултат."
+
 #, c-format
 msgid ""
 "%s\n"
@@ -10728,21 +10809,24 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "опцията „C“ очаква число за аргумент"
 
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Неизвестна стратегия: „%s“"
-
 msgid "--strategy requires --merge or --interactive"
 msgstr ""
 "опцията „--strategy“ изисква някоя от опциите „--merge“ или „--interactive“"
 
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"опциите за прилагане са несъвместими с „rebase.autosquash“.  Пробвайте да "
+"опциите за прилагане са несъвместими с „rebase.autoSquash“.  Пробвайте да "
 "добавите опцията „--no-autosquash“"
 
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"опциите за прилагане са несъвместими с „rebase.rebaseMerges“.  Пробвайте да "
+"добавите опцията „--no-rebase-merges“"
+
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
@@ -10789,9 +10873,6 @@ msgstr "„%s“: изисква се точно една база за преб
 msgid "Does not point to a valid commit '%s'"
 msgstr "Указателят „%s“ не сочи към подаване"
 
-msgid "Please commit or stash them."
-msgstr "Промѐните трябва или да се подадат, или да се скатаят."
-
 msgid "HEAD is up to date."
 msgstr "Указателят „HEAD“ е напълно актуален."
 
@@ -11476,9 +11557,9 @@ msgstr ""
 msgid "approxidate"
 msgstr "евристична дата"
 
-msgid "with -C, expire objects older than this"
+msgid "with --cruft, expire objects older than this"
 msgstr ""
-"с опцията „-C“: обявяване на обектите по-стари от това ВРЕМЕ за остарели"
+"с опцията „--cruft“: обявяване на обектите по-стари от това ВРЕМЕ за остарели"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr ""
@@ -12158,6 +12239,9 @@ msgstr ""
 msgid "remote name"
 msgstr "име на отдалечено хранилище"
 
+msgid "push all refs"
+msgstr "изтласкване на всички указатели"
+
 msgid "use stateless RPC protocol"
 msgstr "използване на протокол без запазване на състоянието за RPC"
 
@@ -12364,9 +12448,11 @@ msgstr ""
 "локалното хранилище"
 
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) ОПЦИЯ…"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) ОПЦИЯ…"
 
 msgid "this worktree is not sparse"
 msgstr "това работно дърво не е частично"
@@ -12492,6 +12578,24 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr "грешка при обновяване на работната директория"
 
+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 "разделяне на входните и изходните файлове с нулевия знак „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 "ползване на шаблоните във ФАЙЛа вместо текущите."
+
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [ОПЦИЯ_ЗА_ЖУРНАЛ…]"
 
@@ -15421,8 +15525,8 @@ msgstr "дължината на съкращаване е извън диапа
 msgid "bad zlib compression level %d"
 msgstr "неправилно ниво на компресиране: %d"
 
-msgid "core.commentChar should only be one character"
-msgstr "настройката „core.commentChar“ трябва да е само един знак"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "настройката „core.commentChar“ трябва да е само един знак от ASCII"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15539,6 +15643,10 @@ msgstr "„%s“ не може да се зададе да е „%s“"
 msgid "invalid section name: %s"
 msgstr "неправилно име на раздел: %s"
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr "ред %2$<PRIuMAX> в „%1$s“ е прекалено дълъг"
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr "липсва стойност за „%s“"
@@ -16235,6 +16343,9 @@ msgstr "добавяне на допълнителен префикс за вс
 msgid "do not show any source or destination prefix"
 msgstr "без префикс за източника и целта"
 
+msgid "use default prefixes a/ and b/"
+msgstr "ползване на стандартните префикси „a/“ и „b/“"
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
 "извеждане на контекст между последователните парчета с разлики от указания "
@@ -16541,6 +16652,14 @@ msgstr "директорията на git не може да се мигрира
 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 "„%s“ не може да се редактира"
+
 msgid "Filtering content"
 msgstr "Филтриране на съдържанието"
 
@@ -16845,6 +16964,10 @@ msgstr "опцията „-c“ изисква низ за настройка\n"
 msgid "no config key given for --config-env\n"
 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 "непозната опция: „%s“\n"
@@ -18587,6 +18710,10 @@ msgstr "„%s“ липсва в пакет „%s“ при отместване
 msgid "unable to get disk usage of '%s'"
 msgstr "използваното място за съхранение на „%s“ не може да бъде получено"
 
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "неправилна сума за проверка за файла с битови маски „%s“"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "файлът с времето на промяна (mtime) „%s“ е твърде малък"
@@ -18633,6 +18760,14 @@ msgstr ""
 "идентификатор на контролна сума %2$<PRIu32> на файла с обратен индекс „%1$s“ "
 "не се поддържа"
 
+msgid "invalid checksum"
+msgstr "неправилна сума за проверка"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr ""
+"неправилна позиция в обратния индекс при %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
 msgid "cannot both write and verify reverse index"
 msgstr "обратният индекс не може едновременно да се записва и да се проверява"
 
@@ -19378,6 +19513,10 @@ msgstr "непознат аргумент за „%%(%s)“: %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "очаква се положителна широчина с лексемата „%%(align)“"
 
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "очакван формат: %%(ahead-behind:ПОДАВАНЕ)"
+
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "неправилно име на обект: „%.*s“"
@@ -19929,10 +20068,10 @@ msgid_plural ""
 "Your branch and '%s' have diverged,\n"
 "and have %d and %d different commits each, respectively.\n"
 msgstr[0] ""
-"Текущият клон се е отделил от „%s“,\n"
+"Текущият клон се е раздалечил от „%s“,\n"
 "двата имат съответно по %d и %d несъвпадащи подавания.\n"
 msgstr[1] ""
-"Текущият клон се е отделил от „%s“,\n"
+"Текущият клон се е раздалечил от „%s“,\n"
 "двата имат съответно по %d и %d несъвпадащи подавания.\n"
 
 msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
@@ -20011,10 +20150,6 @@ msgstr "конфликтът в „%s“ не може да се обнови"
 msgid "no remembered resolution for '%s'"
 msgstr "липсва запазена корекция на конфликт при „%s“"
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "„%s“ не може да се изтрие"
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "Предварителният вариант на „%s“ е обновен"
@@ -20383,10 +20518,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 "краят на ред не може да се запише в „%s“"
@@ -20757,9 +20888,6 @@ msgstr ""
 "директорията за определянето на последователността „%s“ не може да бъде "
 "създадена"
 
-msgid "could not lock HEAD"
-msgstr "указателят „HEAD“ не може да се заключи"
-
 msgid "no cherry-pick or revert in progress"
 msgstr ""
 "в момента не се извършва отбиране на подавания или пребазиране на клона"
@@ -20862,13 +20990,13 @@ 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 "и променѝ индекса и/или работното дърво.\n"
 
 #, 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"
@@ -21324,10 +21452,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u байт/сек."
 msgstr[1] "%u байта/сек."
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr "„%s“ не може да се редактира"
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "игнориране на подозрително име на подмодул: „%s“"
@@ -23085,13 +23209,17 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) Не може да бъде се изпълни „%s“"
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Ð\94обавÑ\8fне Ð½Ð° â\80\9e%s: %sâ\80\9c Ð¾Ñ\82: â\80\9e%sâ\80\9c\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Ð\9dепÑ\80авилен Ð¸Ð·Ñ\85од Ð¾Ñ\82: â\80\9e%sâ\80\9c."
 
 #, 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 c6d2dd6ecc6138ded82d147b52dd549272830f52..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-03-01 01:20+0000\n"
-"PO-Revision-Date: 2023-03-01 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"
@@ -699,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"
@@ -723,6 +728,23 @@ msgstr "Cometeu els vostres canvis abans de fusionar."
 msgid "Exiting because of unfinished merge."
 msgstr "S'està sortint a causa d'una fusió no terminada."
 
+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 ""
+"Les branques divergents no es poden avançar ràpidament, cal que feu:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"o:\n"
+"\n"
+"\tgit rebase\n"
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "No és possible avançar ràpidament, s'està avortant."
 
@@ -829,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"
@@ -1173,6 +1201,10 @@ msgstr "s'està truncant el nom del fitxer .rej a %.*s.rej"
 msgid "cannot open %s"
 msgstr "no es pot obrir %s"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "no es pot fer «unlink» de «%s»"
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "El tros #%d s'ha aplicat netament."
@@ -1364,6 +1396,11 @@ msgstr "git archive --remote <repositori> [--exec <ordre>] --list"
 msgid "cannot read '%s'"
 msgstr "no es pot llegir «%s»"
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr ""
+"l'especificació de camí «%s» coincideix amb fitxers fora del directori actual"
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "l'especificació de camí «%s» no ha coincidit amb cap fitxer"
@@ -1380,9 +1417,6 @@ msgstr "no és un nom d'objecte vàlid: %s"
 msgid "not a tree object: %s"
 msgstr "no és un objecte d'arbre: %s"
 
-msgid "current working directory is untracked"
-msgstr "no se segueix el directori de treball actual"
-
 #, c-format
 msgid "File not found: %s"
 msgstr "Fitxer no trobat: %s"
@@ -1503,11 +1537,14 @@ msgstr "no es pot fer fstat gitattributes al fitxer «%s»"
 
 #, c-format
 msgid "ignoring overly large gitattributes file '%s'"
-msgstr "s'ignorarà el fitxer «%s» gitattributes per massa gran"
+msgstr "s'ignorarà el fitxer «%s» gitattributes per ser massa gran"
 
 #, c-format
 msgid "ignoring overly large gitattributes blob '%s'"
-msgstr "s'ignorarà la blob «%s» gitattributes per massa gran"
+msgstr "s'ignorarà el blob «%s» gitattributes per ser massa gran"
+
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "--attr-source incorrecte o GIT_ATTR_SOURCE"
 
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
@@ -1615,9 +1652,6 @@ msgstr[1] "Bisecant: manquen %d revisions a provar després d'aquesta %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents i --reverse no funcionen bé juntes."
 
-msgid "cannot use --contents with final commit object name"
-msgstr "no es pot usar --contents amb el nom d'objecte de la comissió final"
-
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse i --first-parent junts requereixen una última comissió especificada"
@@ -1737,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"
@@ -1802,10 +1838,6 @@ msgstr "submòdul «%s»: no es pot crear la branca: «%s»"
 msgid "'%s' is already checked out at '%s'"
 msgstr "«%s» ja s'ha agafat a «%s»"
 
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "HEAD de l'arbre de treball %s no està actualitzat"
-
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<opcions>] [--] <especificació-de-camí>..."
 
@@ -1813,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:"
 
@@ -2253,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"
 
@@ -2709,7 +2726,7 @@ msgid "show raw timestamp (Default: off)"
 msgstr "mostra la marca de temps en cru (per defecte: desactivat)"
 
 msgid "show long commit SHA1 (Default: off)"
-msgstr "mostra l'SHA1 de comissió llarg (per defecte: desactivat)"
+msgstr "mostra l'SHA1 de la comissió en format llarg (per defecte: desactivat)"
 
 msgid "suppress author name and timestamp (Default: off)"
 msgstr "omet el nom d'autor i la marca de temps (per defecte: desactivat)"
@@ -2858,6 +2875,14 @@ msgstr "No es pot suprimir la branca «%s» agafada a «%s»"
 msgid "remote-tracking branch '%s' not found."
 msgstr "no s'ha trobat la branca amb seguiment remot «%s»."
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"no s'ha trobat la branca «%s».\n"
+"Us heu oblidat de --remote?"
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "no s'ha trobat la branca «%s»."
@@ -2888,6 +2913,10 @@ msgstr "S'està fent «rebase» en la branca %s a %s"
 msgid "Branch %s is being bisected at %s"
 msgstr "La branca %s s'està bisecant a %s"
 
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "HEAD de l'arbre de treball %s no està actualitzat"
+
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Nom de branca no vàlid: «%s»"
@@ -2992,6 +3021,9 @@ msgstr "mou/canvia de nom una branca i el seu registre de referència"
 msgid "move/rename a branch, even if target exists"
 msgstr "mou/canvia de nom una branca, encara que el destí existeixi"
 
+msgid "do not output a newline after empty formatted refs"
+msgstr "no emetis cap línia nova després de refs amb format buit"
+
 msgid "copy a branch and its reflog"
 msgstr "copia una branca i el seu registre de referència"
 
@@ -3210,12 +3242,10 @@ msgid "Created new report at '%s'.\n"
 msgstr "S'ha creat un nou informe a «%s».\n"
 
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<versió>] <fitxer> <git-rev-list-args>"
 
 msgid "git bundle verify [-q | --quiet] <file>"
@@ -3236,11 +3266,11 @@ msgstr "no mostris l'indicador de progrés"
 msgid "show progress meter"
 msgstr "mostra l'indicador de progrés"
 
-msgid "show progress meter during object writing phase"
-msgstr "mostra l'indicador de progrés durant la fase d'escriptura d'objectes"
+msgid "historical; same as --progress"
+msgstr "històric; el mateix que --progress"
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "similar a --all-progress quan l'indicador de progrés es mostra"
+msgid "historical; does nothing"
+msgstr "històric; no fa res"
 
 msgid "specify bundle format version"
 msgstr "especifica la versió del format del farcell"
@@ -3299,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"
@@ -3351,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"
 
@@ -4214,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"
 
@@ -4249,13 +4276,17 @@ msgstr "s'ha produït un error en fer stat a «%s»"
 msgid "%s exists and is not a directory"
 msgstr "%s existeix i no és directori"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "«%s» és un enllaç simbòlic, es rebutja clonar amb --local"
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "no s'ha pogut iniciar l'iterador sobre «%s»"
 
 #, c-format
 msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "l'enllaç simbòlic «%s» existeix, es nega a clonar amb --local"
+msgstr "l'enllaç simbòlic «%s» existeix, es rebutja a clonar amb --local"
 
 #, c-format
 msgid "failed to unlink '%s'"
@@ -4657,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"
 
@@ -4716,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"
@@ -5157,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 ""
@@ -5263,7 +5297,7 @@ msgid "writing to stdin is not supported"
 msgstr "no s'admet escriure a stdin"
 
 msgid "writing config blobs is not supported"
-msgstr "no s'ha admet l'escriptura de blobs de configuració"
+msgstr "no s'admet l'escriptura de blobs de configuració"
 
 #, c-format
 msgid ""
@@ -5436,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 ""
@@ -5778,119 +5812,13 @@ msgstr "git fetch --all [<opcions>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel no pot ser negatiu"
 
-msgid "fetch from all remotes"
-msgstr "obtén de tots els remots"
-
-msgid "set upstream for git pull/fetch"
-msgstr "estableix la font per a git pull/fetch"
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "annexa a .git/FETCH_HEAD en lloc de sobreescriure'l"
-
-msgid "use atomic transaction to update references"
-msgstr "usa una transacció atòmica per a actualitzar les referències"
-
-msgid "path to upload pack on remote end"
-msgstr "camí al qual pujar el paquet al costat remot"
-
-msgid "force overwrite of local reference"
-msgstr "força la sobreescriptura de la referència local"
-
-msgid "fetch from multiple remotes"
-msgstr "obtén de múltiples remots"
-
-msgid "fetch all tags and associated objects"
-msgstr "obtén totes les etiquetes i tots els objectes associats"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "no obtinguis les etiquetes (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "nombre de submòduls obtinguts en paral·lel"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"modifica l'especificació de referència per a col·locar totes les referències "
-"dins de refs/prefetch/"
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr "poda les branques amb seguiment remot que ja no estiguin en el remot"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
-"poda les etiquetes locals que ja no existeixen al remot i adjunta les "
-"etiquetes que han canviat"
-
-msgid "on-demand"
-msgstr "sota demanda"
-
-msgid "control recursive fetching of submodules"
-msgstr "controla l'obtenció recursiva de submòduls"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "escriu les referències obtingudes al fitxer FETCH_HEAD"
-
-msgid "keep downloaded pack"
-msgstr "retén el paquet baixat"
-
-msgid "allow updating of HEAD ref"
-msgstr "permet l'actualització de la referència HEAD"
-
-msgid "deepen history of shallow clone"
-msgstr "aprofundeix la història d'un clon superficial"
-
-msgid "deepen history of shallow repository based on time"
-msgstr "aprofundeix la història d'un clon superficial basat en una data"
-
-msgid "convert to a complete repository"
-msgstr "converteix en un repositori complet"
-
-msgid "re-fetch without negotiating common commits"
-msgstr "tornar a obtenir sense negociar comissions comunes"
-
-msgid "prepend this to submodule path output"
-msgstr "anteposa això a la sortida de camí del submòdul"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"per defecte per a l'obtenció recursiva de submòduls (prioritat més baixa que "
-"els fitxers de configuració)"
-
-msgid "accept refs that update .git/shallow"
-msgstr "accepta les referències que actualitzin .git/shallow"
-
-msgid "refmap"
-msgstr "mapa de referències"
-
-msgid "specify fetch refmap"
-msgstr "específica l'obtenció del mapa de referències"
-
-msgid "report that we have only objects reachable from this object"
-msgstr "informa que només hi ha objectes abastables des d'aquest objecte"
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-"no obtinguis un fitxer de paquet; en canvi, mostra els avantpassats dels "
-"consells de negociació"
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr "executa «maintenance --auto» després d'obtenir"
-
-msgid "check for forced-updates on all updated branches"
-msgstr ""
-"comprova si hi ha actualitzacions forçades a totes les branques actualitzades"
-
-msgid "write the commit-graph after fetching"
-msgstr "escriu el graf de comissions després de recollir"
-
-msgid "accept refspecs from stdin"
-msgstr "llegeix les especificacions de referència des de stdin"
-
 msgid "couldn't find remote ref HEAD"
 msgstr "no s'ha pogut trobar la referència HEAD remota"
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "De %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "objecte %s no trobat"
@@ -5963,10 +5891,6 @@ msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr ""
 "s'ha rebutjat %s perquè no es permeten actualitzar les arrels superficials"
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "De %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -6060,6 +5984,116 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "necessiteu especificar un nom d'etiqueta"
 
+msgid "fetch from all remotes"
+msgstr "obtén de tots els remots"
+
+msgid "set upstream for git pull/fetch"
+msgstr "estableix la font per a git pull/fetch"
+
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "annexa a .git/FETCH_HEAD en lloc de sobreescriure'l"
+
+msgid "use atomic transaction to update references"
+msgstr "usa una transacció atòmica per a actualitzar les referències"
+
+msgid "path to upload pack on remote end"
+msgstr "camí al qual pujar el paquet al costat remot"
+
+msgid "force overwrite of local reference"
+msgstr "força la sobreescriptura de la referència local"
+
+msgid "fetch from multiple remotes"
+msgstr "obtén de múltiples remots"
+
+msgid "fetch all tags and associated objects"
+msgstr "obtén totes les etiquetes i tots els objectes associats"
+
+msgid "do not fetch all tags (--no-tags)"
+msgstr "no obtinguis les etiquetes (--no-tags)"
+
+msgid "number of submodules fetched in parallel"
+msgstr "nombre de submòduls obtinguts en paral·lel"
+
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"modifica l'especificació de referència per a col·locar totes les referències "
+"dins de refs/prefetch/"
+
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "poda les branques amb seguiment remot que ja no estiguin en el remot"
+
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr ""
+"poda les etiquetes locals que ja no existeixen al remot i adjunta les "
+"etiquetes que han canviat"
+
+msgid "on-demand"
+msgstr "sota demanda"
+
+msgid "control recursive fetching of submodules"
+msgstr "controla l'obtenció recursiva de submòduls"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "escriu les referències obtingudes al fitxer FETCH_HEAD"
+
+msgid "keep downloaded pack"
+msgstr "retén el paquet baixat"
+
+msgid "allow updating of HEAD ref"
+msgstr "permet l'actualització de la referència HEAD"
+
+msgid "deepen history of shallow clone"
+msgstr "aprofundeix la història d'un clon superficial"
+
+msgid "deepen history of shallow repository based on time"
+msgstr "aprofundeix la història d'un clon superficial basat en una data"
+
+msgid "convert to a complete repository"
+msgstr "converteix en un repositori complet"
+
+msgid "re-fetch without negotiating common commits"
+msgstr "tornar a obtenir sense negociar comissions comunes"
+
+msgid "prepend this to submodule path output"
+msgstr "anteposa això a la sortida de camí del submòdul"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"per defecte per a l'obtenció recursiva de submòduls (prioritat més baixa que "
+"els fitxers de configuració)"
+
+msgid "accept refs that update .git/shallow"
+msgstr "accepta les referències que actualitzin .git/shallow"
+
+msgid "refmap"
+msgstr "mapa de referències"
+
+msgid "specify fetch refmap"
+msgstr "específica l'obtenció del mapa de referències"
+
+msgid "report that we have only objects reachable from this object"
+msgstr "informa que només hi ha objectes abastables des d'aquest objecte"
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+"no obtinguis un fitxer de paquet; en canvi, mostra els avantpassats dels "
+"consells de negociació"
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr "executa «maintenance --auto» després d'obtenir"
+
+msgid "check for forced-updates on all updated branches"
+msgstr ""
+"comprova si hi ha actualitzacions forçades a totes les branques actualitzades"
+
+msgid "write the commit-graph after fetching"
+msgstr "escriu el graf de comissions després de recollir"
+
+msgid "accept refspecs from stdin"
+msgstr "llegeix les especificacions de referència des de stdin"
+
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only necessita un o més --negotiation-tip=*"
 
@@ -6176,6 +6210,12 @@ msgstr "imprimeix només les referències que continguin la comissió"
 msgid "print only refs which don't contain the commit"
 msgstr "imprimeix només les referències que no continguin la comissió"
 
+msgid "read reference patterns from stdin"
+msgstr "llegeix els patrons de referència de l'entrada estàndard"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "s'han proporcionat arguments desconeguts amb --stdin"
+
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<config> [--] <arguments>"
 
@@ -6188,6 +6228,10 @@ msgstr "clau de configuració emmagatzemant una llista de camins de repositori"
 msgid "missing --config=<config>"
 msgstr "falta --config=<config>"
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "s'ha obtingut una configuració incorrecta --config=%s"
+
 msgid "unknown"
 msgstr "desconegut"
 
@@ -6334,19 +6378,28 @@ msgstr "%s: la HEAD separada no apunta a res"
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "avís: %s apunta a una branca no nascuda (%s)"
 
-msgid "Checking cache tree"
-msgstr "S'està comprovant l'arbre de la memòria cau"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "S'està comprovant l'arbre de la memòria cau %s"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s: apuntador sha1 no vàlid a l'arbre de la memòria cau"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: punter sha1 no vàlid a l'arbre de la memòria cau %s"
 
 msgid "non-tree in cache-tree"
 msgstr "un no arbre en l'arbre de la memòria cau"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s: el punter sha1 no és vàlid a «resolve-undo»"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: punter sha1 no vàlid a «resolve-undo» de %s"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "no s'ha pogut carregar l'índex de reversió per al paquet «%s»"
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "rev-index no vàlid per al paquet «%s»"
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -7336,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"
@@ -7846,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 «(»"
@@ -7990,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 «(»"
@@ -8729,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 ""
@@ -8878,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 "
@@ -9236,6 +9231,12 @@ msgstr "versió d'índex no compatible %s"
 msgid "bad index version '%s'"
 msgstr "versió d'índex incorrecta «%s»"
 
+msgid "show progress meter during object writing phase"
+msgstr "mostra l'indicador de progrés durant la fase d'escriptura d'objectes"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "similar a --all-progress quan l'indicador de progrés es mostra"
+
 msgid "<version>[,<offset>]"
 msgstr "<versió>[,<desplaçament>]"
 
@@ -9435,8 +9436,14 @@ msgstr ""
 "i feu-nos saber que encara l'useu enviant un correu electrònic\n"
 "a <git@vger.kernel.org>.  Gràcies.\n"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+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] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <patró>] [--exclude <patró>]"
 
 msgid "pack everything"
 msgstr "empaqueta-ho tot"
@@ -9444,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]"
 
@@ -9502,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."
@@ -9609,8 +9628,8 @@ msgstr ""
 msgid "pull with rebase"
 msgstr "baixar fent «rebase»"
 
-msgid "please commit or stash them."
-msgstr "cometeu-los o emmagatzemeu-los."
+msgid "Please commit or stash them."
+msgstr "Cometeu-los o emmagatzemeu-los."
 
 #, c-format
 msgid ""
@@ -9769,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 ""
@@ -9822,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"
@@ -9854,7 +9869,7 @@ msgstr "valor no vàlid per a «%s»"
 msgid "repository"
 msgstr "repositori"
 
-msgid "push all refs"
+msgid "push all branches"
 msgstr "puja totes les referències"
 
 msgid "mirror all refs"
@@ -9863,8 +9878,8 @@ msgstr "reflecteix totes les referències"
 msgid "delete refs"
 msgstr "suprimeix les referències"
 
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "puja les etiquetes (no es pot usar amb --all o --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr "puja les etiquetes (no es pot usar amb --all, --branches o --mirror)"
 
 msgid "force updates"
 msgstr "força les actualitzacions"
@@ -10129,6 +10144,10 @@ msgstr ""
 "\n"
 "Com a resultat, git no pot fer un «rebase» d'elles."
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Mode de fusió de rebase desconegut: %s"
+
 #, c-format
 msgid "could not switch to %s"
 msgstr "no s'ha pogut commutar a %s"
@@ -10143,6 +10162,15 @@ msgid ""
 msgstr ""
 "tipus buit no reconegut «%s»; els valors vàlids són «drop», «keep» i «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 amb un argument de cadena buit està obsolet i deixarà de "
+"funcionar en una versió futura del Git. Utilitzeu --rebase-merges sense un "
+"argument, que fa el mateix."
+
 #, c-format
 msgid ""
 "%s\n"
@@ -10357,20 +10385,23 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "«switch» «c» espera un valor numèric"
 
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Mode desconegut: %s"
-
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy requereix --merge o --interactive"
 
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"les opcions «apply» són incompatibles amb rebase.autosquash. Considereu "
+"les opcions «apply» són incompatibles amb rebase.autoSquash. Considereu "
 "afegir-hi --no-autosquash"
 
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"les opcions «apply» són incompatibles amb rebase.rebaseMerges. Considereu "
+"afegir-hi --no-rebase-merges"
+
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
@@ -10415,9 +10446,6 @@ msgstr "«%s»: necessita exactament una base de fusió"
 msgid "Does not point to a valid commit '%s'"
 msgstr "No apunta a una comissió vàlida «%s»"
 
-msgid "Please commit or stash them."
-msgstr "Cometeu-los o emmagatzemeu-los."
-
 msgid "HEAD is up to date."
 msgstr "HEAD està al dia."
 
@@ -10677,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"
@@ -11091,8 +11120,8 @@ msgstr ""
 msgid "approxidate"
 msgstr "data aproximada"
 
-msgid "with -C, expire objects older than this"
-msgstr "amb -C, venç els objectes més antics que aquest"
+msgid "with --cruft, expire objects older than this"
+msgstr "amb --cruft, vencen els objectes més antics que aquest"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "elimina els paquets redundants, i executeu git-prune-packed"
@@ -11764,6 +11793,9 @@ msgstr ""
 msgid "remote name"
 msgstr "nom del remot"
 
+msgid "push all refs"
+msgstr "puja totes les referències"
+
 msgid "use stateless RPC protocol"
 msgstr "usa el protocol RPC sense estat"
 
@@ -11968,9 +12000,11 @@ msgid "show refs from stdin that aren't in local repository"
 msgstr "mostra les referències de stdin que no siguin en el repositori local"
 
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<opcions>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<opcions>]"
 
 msgid "this worktree is not sparse"
 msgstr "aquest arbre de treball no és dispers"
@@ -12094,6 +12128,24 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr "s'ha produït un error en actualitzar el directori de treball"
 
+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 <fitxer>]"
+
+msgid "terminate input and output files by a NUL character"
+msgstr "acaba els fitxers d'entrada i de sortida amb un caràcter NUL"
+
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
+"quan s'utilitza amb --rules-file, interpreta els patrons com a patrons del "
+"mode con"
+
+msgid "use patterns in <file> instead of the current ones."
+msgstr "utilitza patrons en <file> en lloc dels actuals."
+
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [<log-options>]"
 
@@ -12619,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"
@@ -13373,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]]"
@@ -13396,8 +13452,39 @@ msgstr "git worktree remove [-f] <worktree>"
 msgid "git worktree repair [<path>...]"
 msgstr "git worktree repair [<camí>...]"
 
-msgid "git worktree unlock <worktree>"
-msgstr "git worktree unlock <worktree>"
+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"
@@ -13470,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"
 
@@ -13483,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"
 
@@ -13504,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"
 
@@ -13735,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"
 
@@ -13968,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"
@@ -14387,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 ""
@@ -14482,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"
 
@@ -14516,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 ""
@@ -14570,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ó!"
@@ -14748,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"
@@ -14994,8 +15137,8 @@ msgstr "la longitud d'«abbrev» està fora de rang: %d"
 msgid "bad zlib compression level %d"
 msgstr "nivell de compressió de zlib incorrecte %d"
 
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar només hauria de ser un caràcter"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar només hauria de ser un caràcter ASCII"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15107,6 +15250,11 @@ msgstr "no s'ha pogut establir «%s» a «%s»"
 msgid "invalid section name: %s"
 msgstr "nom de secció no vàlida: %s"
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr ""
+"es rebutja treballar amb una línia massa llarga a «%s» a la línia %<PRIuMAX>"
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr "falta el valor per «%s»"
@@ -15521,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í>"
 
@@ -15581,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"
@@ -15595,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"
@@ -15790,6 +15948,9 @@ msgstr "afegir un prefix addicional per a cada línia de sortida"
 msgid "do not show any source or destination prefix"
 msgstr "no mostris cap prefix d'origen o destí"
 
+msgid "use default prefixes a/ and b/"
+msgstr "utilitza els prefixos per defecte a/ i b/"
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
 "mostra el context entre trossos de diferència fins al nombre especificat de "
@@ -16101,6 +16262,14 @@ msgstr "no s'ha pogut migrar el directori de «%s» a «%s»"
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "consell: s'està esperant que el vostre editor tanqui el fitxer...%c"
 
+#, c-format
+msgid "could not write to '%s'"
+msgstr "no s'ha pogut escriure a «%s»"
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr "no s'ha pogut editar «%s»"
+
 msgid "Filtering content"
 msgstr "S'està filtrant el contingut"
 
@@ -16398,6 +16567,10 @@ msgstr "-c espera una cadena de configuració\n"
 msgid "no config key given for --config-env\n"
 msgstr "no s'ha indicat cap clau de configuració per a --config-env\n"
 
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "no s'ha donat d'atribut font per a --attr-source\n"
+
 #, c-format
 msgid "unknown option: %s\n"
 msgstr "opció desconeguda: %s\n"
@@ -16866,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"
@@ -17768,7 +17941,7 @@ msgid "object fails fsck: %s"
 msgstr "l'objecte ha fallat fsck: %s"
 
 msgid "refusing to create malformed object"
-msgstr "es nega a crear un objecte mal format"
+msgstr "es rebutja crear un objecte mal format"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -18109,6 +18282,10 @@ msgstr "no s'ha pogut trobar «%s» al paquet «%s» al desplaçament %<PRIuMAX>
 msgid "unable to get disk usage of '%s'"
 msgstr "no s'ha pogut obtenir l'ús del disc de «%s»"
 
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "el fitxer de mapa de bits «%s» té una suma de verificació no vàlida"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "el fitxer mtimes %s és massa petit"
@@ -18149,6 +18326,14 @@ msgstr "el fitxer d'índex invers %s té la versió %<PRIu32> no admesa"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "el fitxer d'índex invers %s té un ID de resum %<PRIu32> no admès"
 
+msgid "invalid checksum"
+msgstr "suma de verificació no vàlida"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr ""
+"posició no vàlida de l'índex de reversió a %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
 msgid "cannot both write and verify reverse index"
 msgstr "no es pot escriure i verificar l'índex invers"
 
@@ -18500,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)"
@@ -18651,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"
@@ -18767,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
@@ -18854,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)"
@@ -18878,6 +19094,10 @@ msgstr "argument %%(%s) desconegut: %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "amplada positiva esperada amb l'àtom %%(align)"
 
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "format esperat: %%(ahead-behind:<committish>)"
+
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "nom de camp mal format: %.*s"
@@ -18925,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)"
@@ -18986,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"
@@ -19439,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'"
@@ -19512,10 +19740,6 @@ msgstr "ha fallat en actualitzar l'estat en conflicte a «%s»"
 msgid "no remembered resolution for '%s'"
 msgstr "no hi ha cap resolució recordada per a «%s»"
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "no es pot fer «unlink» de «%s»"
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "Imatge prèvia actualitzada per a «%s»"
@@ -19556,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"
 
@@ -19854,10 +20082,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "no s'ha pogut bloquejar «%s»"
 
-#, c-format
-msgid "could not write to '%s'"
-msgstr "no s'ha pogut escriure a «%s»"
-
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "no s'ha pogut escriure el terminador de línia a «%s»"
@@ -20221,9 +20445,6 @@ msgstr "intenteu «git cherry-pick (--continue | %s--abort | --quit)»"
 msgid "could not create sequencer directory '%s'"
 msgstr "no s'ha pogut crear el directori de seqüenciador «%s»"
 
-msgid "could not lock HEAD"
-msgstr "no s'ha pogut bloquejar HEAD"
-
 msgid "no cherry-pick or revert in progress"
 msgstr "ni hi ha cap «cherry pick» ni cap reversió en curs"
 
@@ -20318,13 +20539,13 @@ msgstr ""
 " git rebase --continue\n"
 "\n"
 
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "i ha fet canvis a l'índex i/o l'arbre de treball\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "i ha fet canvis a l'índex i/o a l'arbre de treball.\n"
 
 #, 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"
@@ -20334,7 +20555,8 @@ msgstr ""
 "però ha deixat canvis a l'índex i/o l'arbre de treball\n"
 "Cometeu o feu «stash» dels vostres canvis, i llavors executeu\n"
 "\n"
-" git rebase --continue\n"
+"  git rebase --continue\n"
+"\n"
 
 #, c-format
 msgid "illegal label name: '%.*s'"
@@ -20720,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)"
@@ -20771,10 +21064,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u byte/s"
 msgstr[1] "%u bytes/s"
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr "no s'ha pogut editar «%s»"
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "s'està ignorant el nom de submòdul sospitós %s"
@@ -22512,13 +22801,17 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) no s'ha pogut executar «%s»"
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) S'està afegint %s: %s des de: «%s»\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Sortida mal formada de «%s»"
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) s'ha produït un error en tancar el conducte «%s»"
 
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) S'està afegint %s: %s des de: «%s»\n"
+
 msgid "cannot send message as 7bit"
 msgstr "no es pot enviar el missatge en 7 bits"
 
@@ -22555,367 +22848,3 @@ msgstr "S'està ometent %s amb el sufix de còpia de seguretat «%s».\n"
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Esteu segur que voleu enviar %s? [y|N]: "
-
-#~ msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-#~ msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
-
-#~ msgid "won't bisect on cg-seek'ed tree"
-#~ msgstr "no es bisecarà en un arbre en el qual s'ha fet cg-seek"
-
-#~ msgid "--bisect-terms requires 0 or 1 argument"
-#~ msgstr "--bisect-terms requereix 0 o 1 argument"
-
-#~ msgid "--bisect-next requires 0 arguments"
-#~ msgstr "--bisect-next no requereix cap argument"
-
-#~ msgid "--bisect-log requires 0 arguments"
-#~ msgstr "--bisect-log no requereix cap argument"
-
-#~ msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-#~ msgstr "git env--helper --type=[bool|ulong] <opcions> <env-var>"
-
-#~ msgid "default for git_env_*(...) to fall back on"
-#~ msgstr "valor per defecte per a git_env_*(...) en cas d'absència"
-
-#~ msgid "be quiet only use git_env_*() value as exit code"
-#~ msgstr "silenciós només utilitza el valor git_env_*() com a codi de sortida"
-
-#, c-format
-#~ msgid ""
-#~ "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-#~ msgstr ""
-#~ "l'opció «--default» espera un valor booleà amb «--type=bool», no «%s»"
-
-#, c-format
-#~ msgid ""
-#~ "option `--default' expects an unsigned long value with `--type=ulong`, "
-#~ "not `%s`"
-#~ msgstr ""
-#~ "l'opció «--default» espera un valor llarg sense signe amb «--type=ulong», "
-#~ "no «%s»"
-
-#, c-format
-#~ msgid "%s doesn't support --super-prefix"
-#~ msgstr "%s no admet --super-prefix"
-
-#, c-format
-#~ msgid "no prefix given for --super-prefix\n"
-#~ msgstr "no s'ha especificat cap prefix per a --super-prefix\n"
-
-#, c-format
-#~ msgid "failed to read object %s"
-#~ msgstr "s'ha produït un error en llegir l'objecte %s"
-
-#~ msgid "file write error"
-#~ msgstr "s'ha produït un error en escriure al fitxer"
-
-#~ msgid "corrupt commit"
-#~ msgstr "comissió corrupta"
-
-#~ msgid "corrupt tag"
-#~ msgstr "etiqueta corrupta"
-
-#, c-format
-#~ msgid "%%(objecttype) does not take arguments"
-#~ msgstr "%%(objecttype) no accepta arguments"
-
-#, c-format
-#~ msgid "%%(deltabase) does not take arguments"
-#~ msgstr "%%(deltabase) no accepta arguments"
-
-#, c-format
-#~ msgid "%%(body) does not take arguments"
-#~ msgstr "%%(body) no accepta arguments"
-
-#, c-format
-#~ msgid "unrecognized email option: %s"
-#~ msgstr "opció del correu electrònic no reconeguda: «%s»"
-
-#, 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')."
-#~ msgstr ""
-#~ "S'ha trigat %.2f segons enumerar els fitxers no seguits.\n"
-#~ "«status -uno» pot accelerar-ho, però heu d'anar amb compte de no\n"
-#~ "oblidar-vos d'afegir fitxers nous vosaltres mateixos (vegeu\n"
-#~ "«git help status»)."
-
-#, 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] "modificat %d camí\n"
-#~ msgstr[1] "modificat %d camins\n"
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for staging."
-#~ msgstr ""
-#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
-#~ "immediatament\n"
-#~ "per «staging»."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for stashing."
-#~ msgstr ""
-#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
-#~ "immediatament\n"
-#~ "per «stashing»."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for unstaging."
-#~ msgstr ""
-#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
-#~ "immediatament\n"
-#~ "per «unstaging»."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for applying."
-#~ msgstr ""
-#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
-#~ "immediatament\n"
-#~ "per a aplicar-se."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for discarding."
-#~ msgstr ""
-#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
-#~ "immediatament\n"
-#~ "per a descartar-se."
-
-#, perl-format
-#~ msgid "failed to open hunk edit file for writing: %s"
-#~ msgstr "s'ha produït un error en escriure al fitxer d'edició del tros: %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"
-#~ "Per a eliminar les línies «%s», convertiu-les en línies ' ' (context).\n"
-#~ "Per a eliminar les línies «%s», suprimiu-les.\n"
-#~ "Les línies que comencin per %s s'eliminaran.\n"
-
-#, perl-format
-#~ msgid "failed to open hunk edit file for reading: %s"
-#~ msgstr "s'ha produït un error en llegir al fitxer d'edició del tros: %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 - fes «stage» d'aquest tros\n"
-#~ "n - no facis «stage» d'aquest tros\n"
-#~ "q - surt; no facis «stage» d'aquest tros o de cap altre restant\n"
-#~ "a - fes «stage» d'aquest tros i tota la resta de trossos del fitxer\n"
-#~ "d - no facis «stage» d'aquest tros o de cap altre restant del fitxer"
-
-#~ 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 - fes «stash» d'aquest tros\n"
-#~ "n - no facis «stash» d'aquest tros\n"
-#~ "q - surt; no facis «stash» d'aquest tros o de cap altre restant\n"
-#~ "a - fes «stash» d'aquest tros i tota la resta de trossos del fitxer\n"
-#~ "d - no facis «stash» d'aquest tros o de cap altre restant del fitxer"
-
-#~ 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 - fes «unstage» d'aquest tros\n"
-#~ "n - no facis «unstage» d'aquest tros\n"
-#~ "q - surt; no facis «unstage» d'aquest tros o de cap altre restant\n"
-#~ "a - fes «unstage» d'aquest tros i tota la resta de trossos del fitxer\n"
-#~ "d - no facis «unstage» d'aquest tros o de cap altre restant del fitxer"
-
-#~ 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 - aplica aquest tros a l'índex\n"
-#~ "n - no apliquis aquest tros a l'índex\n"
-#~ "q - surt; no apliquis aquest tros ni cap dels pendents\n"
-#~ "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
-#~ "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-#~ 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 - descarta aquest tros de l'arbre de treball\n"
-#~ "n - no descartis aquest tros des de l'arbre de treball\n"
-#~ "q - surt; no descartis aquest tros ni cap dels pendents\n"
-#~ "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
-#~ "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-#~ 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 - descarta aquest tros de l'índex i de l'arbre de treball\n"
-#~ "n - no descartis aquest tros des de l'índex i de l'arbre de treball\n"
-#~ "q - surt; no descartis aquest tros ni cap dels pendents\n"
-#~ "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
-#~ "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-#~ 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 - aplica aquest tros a l'índex i l'arbre de treball\n"
-#~ "n - no apliquis aquest tros des de l'índex i de l'arbre de treball\n"
-#~ "q - surt; no apliquis aquest tros ni cap dels pendents\n"
-#~ "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
-#~ "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-#~ 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 - aplica aquest tros a l'arbre de treball\n"
-#~ "n - no apliquis aquest tros a l'arbre de treball\n"
-#~ "q - surt; no apliquis aquest tros ni cap dels pendents\n"
-#~ "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
-#~ "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-#~ 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 - selecciona el tros on voleu anar\n"
-#~ "/ - cerca un tros que coincideixi amb l'expressió regular donada\n"
-#~ "j - deixa aquest tros sense decidir, veure el tros sense decidir següent\n"
-#~ "J - deixa aquest tros sense decidir, veure el tros següent\n"
-#~ "k - deixa aquest tros sense decidir, veure el tros sense decidir "
-#~ "anterior\n"
-#~ "K - deixa aquest tros sense decidir, veure el tros anterior\n"
-#~ "s - divideix el tros actual en trossos més petits\n"
-#~ "e - edita manualment el tros actual\n"
-#~ "? - mostra l'ajuda\n"
-
-#~ msgid "The selected hunks do not apply to the index!\n"
-#~ msgstr "Els trossos seleccionats no apliquen a l'índex\n"
-
-#, perl-format
-#~ msgid "ignoring unmerged: %s\n"
-#~ msgstr "s'està ignorant %s no fusionat\n"
-
-#~ msgid "No other hunks to goto\n"
-#~ msgstr "No hi ha altres trossos on anar-hi\n"
-
-#, perl-format
-#~ msgid "Invalid number: '%s'\n"
-#~ msgstr "Número no vàlid: «%s»\n"
-
-#, perl-format
-#~ msgid "Sorry, only %d hunk available.\n"
-#~ msgid_plural "Sorry, only %d hunks available.\n"
-#~ msgstr[0] "Només %d tros disponible.\n"
-#~ msgstr[1] "Només %d trossos disponibles.\n"
-
-#~ msgid "No other hunks to search\n"
-#~ msgstr "No hi ha cap altre tros a cercar\n"
-
-#, perl-format
-#~ msgid "Malformed search regexp %s: %s\n"
-#~ msgstr "Expressió regular de cerca mal formada %s: %s\n"
-
-#~ msgid "No hunk matches the given pattern\n"
-#~ msgstr "No hi ha trossos que coincideixin amb el patró donat\n"
-
-#~ msgid "No previous hunk\n"
-#~ msgstr "Sense tros previ\n"
-
-#~ msgid "No next hunk\n"
-#~ msgstr "No hi ha tros següent\n"
-
-#~ msgid "Sorry, cannot split this hunk\n"
-#~ msgstr "No es pot dividir aquest tros\n"
-
-#, perl-format
-#~ msgid "Split into %d hunk.\n"
-#~ msgid_plural "Split into %d hunks.\n"
-#~ msgstr[0] "Divideix en %d tros.\n"
-#~ msgstr[1] "Divideix en %d trossos.\n"
-
-#~ msgid "Sorry, cannot edit this hunk\n"
-#~ msgstr "No es pot editar aquest tros\n"
-
-#~ 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        - mostra els camins amb canvis\n"
-#~ "update        - afegeix l'estat de l'arbre de treball al conjunt de "
-#~ "canvis «staged»\n"
-#~ "revert        - reverteix el conjunt de canvis de «staged» a la versió "
-#~ "HEAD\n"
-#~ "patch         - selecciona trossos i actualitza'ls selectivament\n"
-#~ "diff          - mostra la diferència entre HEAD i l'índex\n"
-#~ "add untracked - afegeix el contingut dels fitxers no seguits al conjunt "
-#~ "de canvis «staged»\n"
-
-#~ msgid "missing --"
-#~ msgstr "manca --"
-
-#, perl-format
-#~ msgid "unknown --patch mode: %s"
-#~ msgstr "desconegut --patch mode: %s"
-
-#, perl-format
-#~ msgid "invalid argument %s, expecting --"
-#~ msgstr "argument %s no vàlid, s'esperava --"
-
-#, c-format
-#~ msgid "unable to normalize object directory: %s"
-#~ msgstr "no s'ha pogut normalitzar el directori de l'objecte: %s"
index 7559a8c64e4eb799110aa7142a35656c30cdb2b6..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-03-03 17:13+0100\n"
-"PO-Revision-Date: 2023-03-03 13:46+0100\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.2.2\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"
@@ -688,6 +688,24 @@ msgstr "Bitte committen Sie Ihre Änderungen, bevor Sie mergen."
 msgid "Exiting because of unfinished merge."
 msgstr "Beende wegen nicht abgeschlossenem Merge."
 
+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 ""
+"Abweichende Branches können nicht vorgespult werden, benutzen Sie "
+"stattdessen:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"oder:\n"
+"\n"
+"\tgit rebase\n"
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "Vorspulen nicht möglich, breche ab."
 
@@ -798,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"
@@ -1143,6 +1167,10 @@ msgstr "Verkürze Name von .rej Datei zu %.*s.rej"
 msgid "cannot open %s"
 msgstr "kann '%s' nicht öffnen"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "Kann '%s' nicht löschen."
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Patch-Bereich #%d sauber angewendet."
@@ -1340,6 +1368,11 @@ msgstr "git archive --remote <Repository> [--exec <Programm>] --list"
 msgid "cannot read '%s'"
 msgstr "kann '%s' nicht lesen"
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr ""
+"Pfadspezifikation '%s' findet Dateien außerhalb des aktuellen Verzeichnisses"
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
@@ -1356,9 +1389,6 @@ msgstr "Kein gültiger Objektname: %s"
 msgid "not a tree object: %s"
 msgstr "Kein Tree-Objekt: %s"
 
-msgid "current working directory is untracked"
-msgstr "aktuelles Arbeitsverzeichnis ist unversioniert"
-
 #, c-format
 msgid "File not found: %s"
 msgstr "Datei nicht gefunden: %s"
@@ -1485,6 +1515,9 @@ msgstr "ignoriere übermäßig große gitattributes-Datei '%s'"
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "ignoriere übermäßig großen gitattribute-Blob '%s'"
 
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "ungültiges --attr-source oder GIT_ATTR_SOURCE"
+
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Ungültiger Inhalt bzgl. Anführungszeichen in Datei '%s': %s"
@@ -1591,10 +1624,6 @@ msgstr[1] "Binäre Suche: danach noch %d Commits zum Testen übrig %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents und --reverse funktionieren gemeinsam nicht."
 
-msgid "cannot use --contents with final commit object name"
-msgstr ""
-"kann --contents nicht mit endgültigem Namen des Commit-Objektes benutzen"
-
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse und --first-parent zusammen erfordern die Angabe eines "
@@ -1669,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
@@ -1717,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"
@@ -1782,10 +1810,6 @@ msgstr "Submodul '%s': kann Branch nicht erzeugen: '%s'"
 msgid "'%s' is already checked out at '%s'"
 msgstr "'%s' ist bereits in '%s' ausgecheckt"
 
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "HEAD des Arbeitsverzeichnisses %s ist nicht aktualisiert"
-
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<Optionen>] [--] <Pfadspezifikation>..."
 
@@ -1793,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:"
@@ -2251,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"
 
@@ -2848,6 +2858,14 @@ msgstr "Kann Branch '%s' nicht entfernen, ausgecheckt in '%s'."
 msgid "remote-tracking branch '%s' not found."
 msgstr "Remote-Tracking-Branch '%s' nicht gefunden"
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"Branch '%s' nicht gefunden.\n"
+"Haben Sie --remote vergessen?"
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "Branch '%s' nicht gefunden."
@@ -2878,6 +2896,10 @@ msgstr "Branch %s wird auf %s umgesetzt"
 msgid "Branch %s is being bisected at %s"
 msgstr "Binäre Suche von Branch %s zu %s im Gange"
 
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "HEAD des Arbeitsverzeichnisses %s ist nicht aktualisiert"
+
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Ungültiger Branchname: '%s'"
@@ -2983,6 +3005,9 @@ msgid "move/rename a branch, even if target exists"
 msgstr ""
 "einen Branch verschieben/umbenennen, auch wenn das Ziel bereits existiert"
 
+msgid "do not output a newline after empty formatted refs"
+msgstr "keinen Zeilenumbruch nach leer formatierten Referenzen ausgeben"
+
 msgid "copy a branch and its reflog"
 msgstr "einen Branch und dessen Reflog kopieren"
 
@@ -3212,12 +3237,10 @@ msgid "Created new report at '%s'.\n"
 msgstr "Neuer Bericht unter '%s' erstellt.\n"
 
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<Version>] <Datei> <git-rev-list-Argumente>"
 
 msgid "git bundle verify [-q | --quiet] <file>"
@@ -3238,11 +3261,11 @@ msgstr "keine Fortschrittsanzeige anzeigen"
 msgid "show progress meter"
 msgstr "Fortschrittsanzeige anzeigen"
 
-msgid "show progress meter during object writing phase"
-msgstr "Forschrittsanzeige während des Schreibens von Objekten anzeigen"
+msgid "historical; same as --progress"
+msgstr "historisch; dasselbe wie --progress"
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "ähnlich zu --all-progress wenn Fortschrittsanzeige darstellt wird"
+msgid "historical; does nothing"
+msgstr "historisch; kein Effekt"
 
 msgid "specify bundle format version"
 msgstr "Version des Paket-Formats angeben"
@@ -3301,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"
@@ -3353,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"
 
@@ -4237,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"
 
@@ -4274,6 +4294,11 @@ msgstr "Konnte '%s' nicht lesen"
 msgid "%s exists and is not a directory"
 msgstr "%s existiert und ist kein Verzeichnis"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr ""
+"'%s' ist eine symbolische Verknüpfung, verweigere das Klonen mit --local"
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "Fehler beim Starten der Iteration über '%s'"
@@ -4701,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."
 
@@ -4761,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"
@@ -5828,126 +5856,13 @@ msgstr "git fetch --all [<Optionen>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel kann nicht negativ sein"
 
-msgid "fetch from all remotes"
-msgstr "fordert von allen Remote-Repositories an"
-
-msgid "set upstream for git pull/fetch"
-msgstr "Upstream für \"git pull/fetch\" setzen"
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "an .git/FETCH_HEAD anhängen statt zu überschreiben"
-
-msgid "use atomic transaction to update references"
-msgstr "atomare Transaktionen nutzen, um Referenzen zu aktualisieren"
-
-msgid "path to upload pack on remote end"
-msgstr "Pfad des Programms zum Hochladen von Paketen auf der Gegenseite"
-
-msgid "force overwrite of local reference"
-msgstr "das Überschreiben einer lokalen Referenz erzwingen"
-
-msgid "fetch from multiple remotes"
-msgstr "von mehreren Remote-Repositories anfordern"
-
-msgid "fetch all tags and associated objects"
-msgstr "alle Tags und verbundene Objekte anfordern"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "nicht alle Tags anfordern (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "Anzahl der parallel anzufordernden Submodule"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"Refspec verändern, damit alle Referenzen unter refs/prefetch/ platziert "
-"werden"
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr ""
-"Remote-Tracking-Branches entfernen, die sich nicht mehr im Remote-Repository "
-"befinden"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
-"lokale Tags entfernen, die sich nicht mehr im Remote-Repository befinden, "
-"und geänderte Tags aktualisieren"
-
-msgid "on-demand"
-msgstr "bei-Bedarf"
-
-msgid "control recursive fetching of submodules"
-msgstr "rekursive Anforderungen von Submodulen kontrollieren"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "schreibe angeforderte Referenzen in die FETCH_HEAD-Datei"
-
-msgid "keep downloaded pack"
-msgstr "heruntergeladenes Paket behalten"
-
-msgid "allow updating of HEAD ref"
-msgstr "Aktualisierung der \"HEAD\"-Referenz erlauben"
-
-msgid "deepen history of shallow clone"
-msgstr ""
-"die Historie eines Klons mit unvollständiger Historie (shallow) vertiefen"
-
-msgid "deepen history of shallow repository based on time"
-msgstr ""
-"die Historie eines Klons mit unvollständiger Historie (shallow) auf "
-"Zeitbasis\n"
-"vertiefen"
-
-msgid "convert to a complete repository"
-msgstr "zu einem vollständigen Repository konvertieren"
-
-msgid "re-fetch without negotiating common commits"
-msgstr "erneutes Abrufen ohne Aushandeln gemeinsamer Commits"
-
-msgid "prepend this to submodule path output"
-msgstr "dies an die Ausgabe der Submodul-Pfade voranstellen"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"Standard für die rekursive Anforderung von Submodulen (geringere Priorität\n"
-"als Konfigurationsdateien)"
-
-msgid "accept refs that update .git/shallow"
-msgstr "Referenzen, die .git/shallow aktualisieren, akzeptieren"
-
-msgid "refmap"
-msgstr "Refmap"
-
-msgid "specify fetch refmap"
-msgstr "Refmap für 'fetch' angeben"
-
-msgid "report that we have only objects reachable from this object"
-msgstr ""
-"ausgeben, dass wir nur Objekte haben, die von diesem Objekt aus erreichbar "
-"sind"
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-"keine Packdatei anfordern; stattdessen die Vorgänger der Verhandlungstipps "
-"anzeigen"
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr "führe 'maintenance --auto' nach \"fetch\" aus"
-
-msgid "check for forced-updates on all updated branches"
-msgstr "Prüfe auf erzwungene Aktualisierungen in allen aktualisierten Branches"
-
-msgid "write the commit-graph after fetching"
-msgstr "Schreibe den Commit-Graph nach \"fetch\""
-
-msgid "accept refspecs from stdin"
-msgstr "akzeptiere Refspecs von der Standard-Eingabe"
-
 msgid "couldn't find remote ref HEAD"
 msgstr "konnte Remote-Referenz von HEAD nicht finden"
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "Von %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "Objekt %s nicht gefunden"
@@ -6021,10 +5936,6 @@ msgstr ""
 "%s zurückgewiesen, da Root-Commits von Repositories mit unvollständiger\n"
 "Historie (shallow) nicht aktualisiert werden dürfen."
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "Von %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -6117,6 +6028,123 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "Sie müssen den Namen des Tags angeben"
 
+msgid "fetch from all remotes"
+msgstr "fordert von allen Remote-Repositories an"
+
+msgid "set upstream for git pull/fetch"
+msgstr "Upstream für \"git pull/fetch\" setzen"
+
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "an .git/FETCH_HEAD anhängen statt zu überschreiben"
+
+msgid "use atomic transaction to update references"
+msgstr "atomare Transaktionen nutzen, um Referenzen zu aktualisieren"
+
+msgid "path to upload pack on remote end"
+msgstr "Pfad des Programms zum Hochladen von Paketen auf der Gegenseite"
+
+msgid "force overwrite of local reference"
+msgstr "das Überschreiben einer lokalen Referenz erzwingen"
+
+msgid "fetch from multiple remotes"
+msgstr "von mehreren Remote-Repositories anfordern"
+
+msgid "fetch all tags and associated objects"
+msgstr "alle Tags und verbundene Objekte anfordern"
+
+msgid "do not fetch all tags (--no-tags)"
+msgstr "nicht alle Tags anfordern (--no-tags)"
+
+msgid "number of submodules fetched in parallel"
+msgstr "Anzahl der parallel anzufordernden Submodule"
+
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"Refspec verändern, damit alle Referenzen unter refs/prefetch/ platziert "
+"werden"
+
+msgid "prune remote-tracking branches no longer on remote"
+msgstr ""
+"Remote-Tracking-Branches entfernen, die sich nicht mehr im Remote-Repository "
+"befinden"
+
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr ""
+"lokale Tags entfernen, die sich nicht mehr im Remote-Repository befinden, "
+"und geänderte Tags aktualisieren"
+
+msgid "on-demand"
+msgstr "bei-Bedarf"
+
+msgid "control recursive fetching of submodules"
+msgstr "rekursive Anforderungen von Submodulen kontrollieren"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "schreibe angeforderte Referenzen in die FETCH_HEAD-Datei"
+
+msgid "keep downloaded pack"
+msgstr "heruntergeladenes Paket behalten"
+
+msgid "allow updating of HEAD ref"
+msgstr "Aktualisierung der \"HEAD\"-Referenz erlauben"
+
+msgid "deepen history of shallow clone"
+msgstr ""
+"die Historie eines Klons mit unvollständiger Historie (shallow) vertiefen"
+
+msgid "deepen history of shallow repository based on time"
+msgstr ""
+"die Historie eines Klons mit unvollständiger Historie (shallow) auf "
+"Zeitbasis\n"
+"vertiefen"
+
+msgid "convert to a complete repository"
+msgstr "zu einem vollständigen Repository konvertieren"
+
+msgid "re-fetch without negotiating common commits"
+msgstr "erneutes Abrufen ohne Aushandeln gemeinsamer Commits"
+
+msgid "prepend this to submodule path output"
+msgstr "dies an die Ausgabe der Submodul-Pfade voranstellen"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"Standard für die rekursive Anforderung von Submodulen (geringere Priorität\n"
+"als Konfigurationsdateien)"
+
+msgid "accept refs that update .git/shallow"
+msgstr "Referenzen, die .git/shallow aktualisieren, akzeptieren"
+
+msgid "refmap"
+msgstr "Refmap"
+
+msgid "specify fetch refmap"
+msgstr "Refmap für 'fetch' angeben"
+
+msgid "report that we have only objects reachable from this object"
+msgstr ""
+"ausgeben, dass wir nur Objekte haben, die von diesem Objekt aus erreichbar "
+"sind"
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+"keine Packdatei anfordern; stattdessen die Vorgänger der Verhandlungstipps "
+"anzeigen"
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr "führe 'maintenance --auto' nach \"fetch\" aus"
+
+msgid "check for forced-updates on all updated branches"
+msgstr "Prüfe auf erzwungene Aktualisierungen in allen aktualisierten Branches"
+
+msgid "write the commit-graph after fetching"
+msgstr "Schreibe den Commit-Graph nach \"fetch\""
+
+msgid "accept refspecs from stdin"
+msgstr "akzeptiere Refspecs von der Standard-Eingabe"
+
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only benötigt einen oder mehrere --negotiation-tip=*"
 
@@ -6239,6 +6267,12 @@ msgstr "nur Referenzen ausgeben, die diesen Commit enthalten"
 msgid "print only refs which don't contain the commit"
 msgstr "nur Referenzen ausgeben, die diesen Commit nicht enthalten"
 
+msgid "read reference patterns from stdin"
+msgstr "Referenzmuster von Standard-Eingabe lesen"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "unbekannte Argumente mit --stdin geliefert"
+
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<Konfiguration> [--] <Argumente>"
 
@@ -6251,6 +6285,10 @@ msgstr "Konfigurationsschlüssel für eine Liste von Repository-Pfaden"
 msgid "missing --config=<config>"
 msgstr "Option --config=<Konfiguration> fehlt"
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "ungültige Konfiguration --config=%s"
+
 msgid "unknown"
 msgstr "unbekannt"
 
@@ -6397,19 +6435,28 @@ msgstr "%s: losgelöster HEAD zeigt auf nichts"
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "Notiz: %s zeigt auf einen ungeborenen Branch (%s)"
 
-msgid "Checking cache tree"
-msgstr "Prüfe Cache-Verzeichnis"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Prüfe Cache-Verzeichnis von %s"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s: Ungültiger SHA1-Zeiger in Cache-Verzeichnis"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: ungültiger SHA1-Zeiger im Cache-Verzeichnis von %s"
 
 msgid "non-tree in cache-tree"
 msgstr "non-tree in Cache-Verzeichnis"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s: Ungültiger sha1-Zeiger in resolve-undo"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: ungültiger SHA1-Zeiger in resolve-undo von %s"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "rev-Index für Pack-Datei '%s' kann nicht geladen werden"
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "ungültiger Rev-Index für Pack-Datei '%s'"
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -6833,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
@@ -7408,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"
@@ -7917,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"
@@ -8066,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"
@@ -8815,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>]"
@@ -8965,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 "
@@ -9326,6 +9314,12 @@ msgstr "nicht unterstützte Index-Version %s"
 msgid "bad index version '%s'"
 msgstr "ungültige Index-Version '%s'"
 
+msgid "show progress meter during object writing phase"
+msgstr "Forschrittsanzeige während des Schreibens von Objekten anzeigen"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "ähnlich zu --all-progress wenn Fortschrittsanzeige darstellt wird"
+
 msgid "<version>[,<offset>]"
 msgstr "<Version>[,<Offset>]"
 
@@ -9530,8 +9524,14 @@ msgstr ""
 "Sie es immer noch verwenden, indem Sie eine E-Mail an\n"
 "<git@vger.kernel.org> senden. Danke.\n"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+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] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <Muster>] [--exclude <Muster>]"
 
 msgid "pack everything"
 msgstr "alles packen"
@@ -9539,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]"
 
@@ -9598,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."
@@ -9712,7 +9724,7 @@ msgstr ""
 msgid "pull with rebase"
 msgstr "Pull mit Rebase"
 
-msgid "please commit or stash them."
+msgid "Please commit or stash them."
 msgstr "Bitte committen Sie die Änderungen oder benutzen Sie \"stash\"."
 
 #, c-format
@@ -9873,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 "
@@ -9909,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 ""
@@ -9930,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"
@@ -9962,8 +9983,8 @@ msgstr "ungültiger Wert für '%s'"
 msgid "repository"
 msgstr "Repository"
 
-msgid "push all refs"
-msgstr "alle Referenzen versenden"
+msgid "push all branches"
+msgstr "alle Branches versenden"
 
 msgid "mirror all refs"
 msgstr "alle Referenzen spiegeln"
@@ -9971,8 +9992,10 @@ msgstr "alle Referenzen spiegeln"
 msgid "delete refs"
 msgstr "Referenzen löschen"
 
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "Tags versenden (kann nicht mit --all oder --mirror verwendet werden)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr ""
+"Tags versenden (kann nicht mit --all, --branches oder --mirror verwendet "
+"werden)"
 
 msgid "force updates"
 msgstr "Aktualisierung erzwingen"
@@ -10241,6 +10264,10 @@ msgstr ""
 "Infolge dessen kann Git auf diesen Revisionen Rebase nicht\n"
 "ausführen."
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Unbekannter rebase-merges Modus: %s"
+
 #, c-format
 msgid "could not switch to %s"
 msgstr "Konnte nicht zu %s wechseln."
@@ -10258,6 +10285,15 @@ msgstr ""
 "nicht erkannter leerer Typ '%s'; gültige Werte sind \"drop\", \"keep\", und "
 "\"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 mit einem leeren String-Argument ist veraltet und wird in "
+"einer zukünftigen Version von Git nicht mehr funktionieren. Verwenden Sie "
+"stattdessen --rebase-merges ohne ein Argument, was dasselbe bewirkt."
+
 #, c-format
 msgid ""
 "%s\n"
@@ -10483,20 +10519,23 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "Schalter `C' erwartet einen numerischen Wert."
 
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Unbekannter Modus: %s"
-
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy erfordert --merge oder --interactive"
 
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"apply-Optionen sind mit rebase.autosquash nicht kompatibel. Erwägen Sie das "
+"apply-Optionen sind mit rebase.autoSquash nicht kompatibel. Erwägen Sie das "
 "Hinzufügen von --no-autosquash"
 
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"apply-Optionen sind nicht kompatibel mit rebase.rebaseMerges. Erwägen Sie "
+"das Hinzufügen von --no-rebase-merges"
+
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
@@ -10541,9 +10580,6 @@ msgstr "'%s': benötige genau eine Merge-Basis"
 msgid "Does not point to a valid commit '%s'"
 msgstr "'%s' zeigt auf keinen gültigen Commit."
 
-msgid "Please commit or stash them."
-msgstr "Bitte committen Sie die Änderungen oder benutzen Sie \"stash\"."
-
 msgid "HEAD is up to date."
 msgstr "HEAD ist aktuell."
 
@@ -10806,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"
@@ -11221,8 +11258,8 @@ msgstr "genau wie -a, unerreichbare überflüssige Objekte separat packen"
 msgid "approxidate"
 msgstr "Datumsangabe"
 
-msgid "with -C, expire objects older than this"
-msgstr "mit -C, Objekte älter als angegeben verfallen lassen"
+msgid "with --cruft, expire objects older than this"
+msgstr "mit --cruft, Objekte verfallen lassen, die älter sind als das"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "redundante Pakete entfernen und \"git-prune-packed\" ausführen"
@@ -11902,6 +11939,9 @@ msgstr ""
 msgid "remote name"
 msgstr "Name des Remote-Repositories"
 
+msgid "push all refs"
+msgstr "alle Referenzen versenden"
+
 msgid "use stateless RPC protocol"
 msgstr "zustandsloses RPC-Protokoll verwenden"
 
@@ -12107,10 +12147,11 @@ msgstr ""
 "Repository befinden"
 
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable"
-"[<Optionen>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<Optionen>]"
 
 msgid "this worktree is not sparse"
 msgstr "dieses Arbeitsverzeichnis ist nicht partiell"
@@ -12241,6 +12282,24 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr "Fehler während der Aktualisierung des Arbeitsverzeichnisses."
 
+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 <Datei>]"
+
+msgid "terminate input and output files by a NUL character"
+msgstr "Eingabe- und Ausgabedateien durch ein NUL-Zeichen abschließen"
+
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
+"bei Verwendung mit --rules-file werden die Muster als Cone-Modus Muster "
+"interpretiert"
+
+msgid "use patterns in <file> instead of the current ones."
+msgstr "Muster aus <Datei> anstelle der aktuellen Muster verwenden"
+
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [<log-Optionen>]"
 
@@ -12773,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"
@@ -13547,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]]"
@@ -13574,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"
@@ -13644,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 "
@@ -13659,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"
 
@@ -13681,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"
 
@@ -13920,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"
 
@@ -14159,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"
@@ -14585,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"
@@ -14668,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"
 
@@ -14699,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 ""
@@ -14747,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!"
@@ -15181,8 +15342,8 @@ msgstr "Länge für Abkürzung von Commit-IDs außerhalb des Bereichs: %d"
 msgid "bad zlib compression level %d"
 msgstr "ungültiger zlib Komprimierungsgrad %d"
 
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar sollte nur ein Zeichen sein"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar sollte nur ein ASCII-Zeichen sein"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15299,6 +15460,11 @@ msgstr "Konnte '%s' nicht zu '%s' setzen."
 msgid "invalid section name: %s"
 msgstr "Ungültiger Sektionsname: %s"
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr ""
+"Ausführung mit übermäßig langer Zeile in '%s' bei Zeile %<PRIuMAX> verweigert"
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr "Fehlender Wert für '%s'"
@@ -15709,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>"
 
@@ -15766,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 ""
@@ -15785,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"
@@ -15980,6 +16156,9 @@ msgstr "einen zusätzlichen Präfix bei jeder Ausgabezeile voranstellen"
 msgid "do not show any source or destination prefix"
 msgstr "keine Quell- oder Ziel-Präfixe anzeigen"
 
+msgid "use default prefixes a/ and b/"
+msgstr "Standardpräfixe a/ und b/ verwenden"
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
 "Kontext zwischen Unterschied-Blöcken bis zur angegebenen Anzahl von Zeilen "
@@ -16294,6 +16473,14 @@ msgstr "Konnte Git-Verzeichnis nicht von '%s' nach '%s' migrieren"
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "Hinweis: Warte auf das Schließen der Datei durch Ihren Editor...%c"
 
+#, c-format
+msgid "could not write to '%s'"
+msgstr "Konnte nicht nach '%s' schreiben."
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr "Konnte '%s' nicht editieren."
+
 msgid "Filtering content"
 msgstr "Filtere Inhalt"
 
@@ -16590,6 +16777,10 @@ msgstr "-c erwartet einen Konfigurationsstring.\n"
 msgid "no config key given for --config-env\n"
 msgstr "kein Konfigurationsschlüssel für --config-env angegeben\n"
 
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "keine Attributquelle für --attr-source angegeben\n"
+
 #, c-format
 msgid "unknown option: %s\n"
 msgstr "Unbekannte Option: %s\n"
@@ -17282,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 ""
@@ -18023,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"
@@ -18032,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.
@@ -18048,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]"
@@ -18303,6 +18494,10 @@ msgstr "konnte '%s' in Paket '%s' bei Offset %<PRIuMAX> nicht finden"
 msgid "unable to get disk usage of '%s'"
 msgstr "Festplattennutzung von '%s' kann nicht abgerufen werden"
 
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "Bitmap-Datei '%s' hat eine ungültige Prüfsumme"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "mtimes-Datei %s ist zu klein"
@@ -18343,6 +18538,13 @@ msgstr "Reverse-Index-Datei %s hat nicht unterstützte Version %<PRIu32>"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "Reverse-Index-Datei %s hat nicht unterstützte Hash-ID %<PRIu32>"
 
+msgid "invalid checksum"
+msgstr "ungültige Prüfsumme"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "ungültige rev-index Position bei %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
 msgid "cannot both write and verify reverse index"
 msgstr ""
 "Reverse-Index kann nicht gleichzeitig geschrieben und verifiziert werden"
@@ -18694,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 ""
@@ -18847,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"
@@ -19047,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)"
@@ -19071,6 +19304,10 @@ msgstr "nicht erkanntes %%(%s) Argument: %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "Positive Breitenangabe für %%(align) erwartet"
 
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "erwartetes Format: %%(ahead-behind:<Commit>)"
+
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "Fehlerhafter Feldname: %.*s"
@@ -19117,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)"
@@ -19178,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"
@@ -19635,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'"
@@ -19710,10 +19954,6 @@ msgstr "Fehler beim Aktualisieren des Konflikt-Status in '%s'."
 msgid "no remembered resolution for '%s'"
 msgstr "Keine aufgezeichnete Konfliktauflösung für '%s'."
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "Kann '%s' nicht löschen."
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "Preimage für '%s' aktualisiert."
@@ -19754,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."
 
@@ -20052,10 +20296,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "Konnte '%s' nicht sperren"
 
-#, c-format
-msgid "could not write to '%s'"
-msgstr "Konnte nicht nach '%s' schreiben."
-
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "Konnte EOL nicht nach '%s' schreiben."
@@ -20424,9 +20664,6 @@ msgstr "versuchen Sie \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgid "could not create sequencer directory '%s'"
 msgstr "konnte \"sequencer\"-Verzeichnis '%s' nicht erstellen"
 
-msgid "could not lock HEAD"
-msgstr "konnte HEAD nicht sperren"
-
 msgid "no cherry-pick or revert in progress"
 msgstr "kein \"cherry-pick\" oder \"revert\" im Gange"
 
@@ -20523,20 +20760,20 @@ msgstr ""
 "\n"
 "ausführen.\n"
 
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "Der Index und/oder das Arbeitsverzeichnis wurde geändert.\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "und Änderungen am Index und/oder am Arbeitsverzeichnis vorgenommen.\n"
 
 #, 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 ""
 "Ausführung erfolgreich: %s\n"
-"Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
+"Aber es sind Änderungen im Index oder Arbeitsverzeichnis verblieben.\n"
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
 "Führen Sie dann aus:\n"
 "\n"
@@ -20930,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)"
@@ -20981,10 +21289,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u Byte/s"
 msgstr[1] "%u Bytes/s"
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr "Konnte '%s' nicht editieren."
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "Ignoriere verdächtigen Submodulnamen: %s"
@@ -22794,13 +23098,17 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) Konnte '%s' nicht ausführen"
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Füge %s: %s hinzu von: '%s'\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Fehlerhafte Ausgabe von '%s'"
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) Fehler beim Schließen der Pipe nach '%s'"
 
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) Füge %s: %s hinzu von: '%s'\n"
+
 msgid "cannot send message as 7bit"
 msgstr "kann Nachricht nicht als 7bit versenden"
 
@@ -22837,377 +23145,3 @@ msgstr "Lasse %s mit Backup-Suffix '%s' aus.\n"
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Wollen Sie %s wirklich versenden? [y|N]: "
-
-#~ msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-#~ msgstr "git bisect--helper --bisect-state (bad|new) [<Commit>]"
-
-#~ msgid "won't bisect on cg-seek'ed tree"
-#~ msgstr ""
-#~ "binäre Suche auf einem durch 'cg-seek' geändertem Verzeichnis nicht "
-#~ "möglich"
-
-#~ msgid "--bisect-terms requires 0 or 1 argument"
-#~ msgstr "--bisect-terms benötigt 0 oder 1 Argument"
-
-#~ msgid "--bisect-next requires 0 arguments"
-#~ msgstr "--bisect-next benötigt 0 Argumente"
-
-#~ msgid "--bisect-log requires 0 arguments"
-#~ msgstr "--bisect-log benötigt 0 Argumente"
-
-#~ msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-#~ msgstr "git env--helper --type=[bool|ulong] <Optionen> <Umgebungsvariable>"
-
-#~ msgid "default for git_env_*(...) to fall back on"
-#~ msgstr "Standard für git_env_*(...), um darauf zurückzugreifen"
-
-#~ msgid "be quiet only use git_env_*() value as exit code"
-#~ msgstr ""
-#~ "Ausgaben unterdrücken; nur git_env_*() Werte als Exit-Code verwenden"
-
-#, c-format
-#~ msgid ""
-#~ "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-#~ msgstr ""
-#~ "Option `--default' erwartet einen booleschen Wert bei `--type=bool`, "
-#~ "nicht `%s`"
-
-#, c-format
-#~ msgid ""
-#~ "option `--default' expects an unsigned long value with `--type=ulong`, "
-#~ "not `%s`"
-#~ msgstr ""
-#~ "Option `--default' erwartet einen vorzeichenlosen Long-Wert bei `--"
-#~ "type=ulong`, nicht `%s`"
-
-#, c-format
-#~ msgid "%s doesn't support --super-prefix"
-#~ msgstr "%s unterstützt kein --super-prefix"
-
-#, c-format
-#~ msgid "no prefix given for --super-prefix\n"
-#~ msgstr "Kein Präfix für --super-prefix angegeben.\n"
-
-#, c-format
-#~ msgid "failed to read object %s"
-#~ msgstr "Konnte Objekt %s nicht lesen."
-
-#~ msgid "file write error"
-#~ msgstr "Fehler beim Schreiben einer Datei."
-
-#~ msgid "corrupt commit"
-#~ msgstr "fehlerhafter Commit"
-
-#~ msgid "corrupt tag"
-#~ msgstr "fehlerhaftes Tag"
-
-#, c-format
-#~ msgid "%%(objecttype) does not take arguments"
-#~ msgstr "%%(objecttype) akzeptiert keine Argumente"
-
-#, c-format
-#~ msgid "%%(deltabase) does not take arguments"
-#~ msgstr "%%(deltabase) akzeptiert keine Argumente"
-
-#, c-format
-#~ msgid "%%(body) does not take arguments"
-#~ msgstr "%%(body) akzeptiert keine Argumente"
-
-#, c-format
-#~ msgid "unrecognized email option: %s"
-#~ msgstr "nicht erkannte E-Mail Option: %s"
-
-#, 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')."
-#~ msgstr ""
-#~ "Es dauerte %.2f Sekunden die unversionierten Dateien zu bestimmen.\n"
-#~ "'status -uno' könnte das beschleunigen, aber Sie müssen darauf achten,\n"
-#~ "neue Dateien selbstständig hinzuzufügen (siehe 'git help status')."
-
-#, perl-format
-#~ msgid "%12s %12s %s"
-#~ msgstr "%28s %25s %s"
-
-#, perl-format
-#~ msgid "touched %d path\n"
-#~ msgid_plural "touched %d paths\n"
-#~ msgstr[0] "%d Pfad angefasst\n"
-#~ msgstr[1] "%d Pfade angefasst\n"
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for staging."
-#~ msgstr ""
-#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-#~ "Patch-Block direkt zum Hinzufügen zur Staging-Area markiert."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for stashing."
-#~ msgstr ""
-#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-#~ "Patch-Block direkt zum Hinzufügen zum Stash markiert."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for unstaging."
-#~ msgstr ""
-#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-#~ "Patch-Block direkt zum Entfernen aus der Staging-Area markiert."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for applying."
-#~ msgstr ""
-#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-#~ "Patch-Block direkt zum Anwenden markiert."
-
-#~ msgid ""
-#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
-#~ "marked for discarding."
-#~ msgstr ""
-#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-#~ "Patch-Block direkt zum Verwerfen markiert."
-
-#, perl-format
-#~ msgid "failed to open hunk edit file for writing: %s"
-#~ msgstr ""
-#~ "Fehler beim Öffnen von Editier-Datei eines Patch-Blocks zum Schreiben: %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"
-#~ "Um '%s' Zeilen zu entfernen, machen Sie aus diesen ' ' Zeilen (Kontext).\n"
-#~ "Um '%s' Zeilen zu entfernen, löschen Sie diese.\n"
-#~ "Zeilen, die mit %s beginnen, werden entfernt.\n"
-
-#, perl-format
-#~ msgid "failed to open hunk edit file for reading: %s"
-#~ msgstr ""
-#~ "Fehler beim Öffnen von Editier-Datei eines Patch-Blocks zum Lesen: %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 - diesen Patch-Block zum Commit vormerken\n"
-#~ "n - diesen Patch-Block nicht zum Commit vormerken\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht zum Commit "
-#~ "vormerken\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei zum Commit "
-#~ "vormerken\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke in dieser Datei nicht zum "
-#~ "Commit vormerken"
-
-#~ 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 - diesen Patch-Block stashen\n"
-#~ "n - diesen Patch-Block nicht stashen\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht stashen\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei stashen\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht stashen"
-
-#~ 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 - diesen Patch-Block unstashen\n"
-#~ "n - diesen Patch-Block nicht unstashen\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht unstashen\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei unstashen\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht unstashen"
-
-#~ 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 - diesen Patch-Block auf den Index anwenden\n"
-#~ "n - diesen Patch-Block nicht auf den Index anwenden\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht auf den "
-#~ "Index anwenden\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei auf den Index "
-#~ "anwenden\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht auf den "
-#~ "Index anwenden"
-
-#~ 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 - diesen Patch-Block im Arbeitsverzeichnis verwerfen\n"
-#~ "n - diesen Patch-Block im Arbeitsverzeichnis nicht verwerfen\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht im "
-#~ "Arbeitsverzeichnis verwerfen\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei im "
-#~ "Arbeitsverzeichnis verwerfen\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht im "
-#~ "Arbeitsverzeichnis verwerfen"
-
-#~ 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 - diesen Patch-Block im Index und Arbeitsverzeichnis verwerfen\n"
-#~ "n - diesen Patch-Block nicht im Index und Arbeitsverzeichnis verwerfen\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht im Index "
-#~ "und Arbeitsverzeichnis verwerfen\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke in der Datei verwerfen\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht verwerfen"
-
-#~ 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 - diesen Patch-Block im Index und auf Arbeitsverzeichnis anwenden\n"
-#~ "n - diesen Patch-Block nicht im Index und auf Arbeitsverzeichnis "
-#~ "anwenden\n"
-#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht anwenden\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
-#~ "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht anwenden"
-
-#~ 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 - diesen Patch-Block auf das Arbeitsverzeichnis anwenden\n"
-#~ "n - diesen Patch-Block nicht auf das Arbeitsverzeichnis anwenden\n"
-#~ "q - Beenden; diesen und alle verbleibenden Patch-Blöcke nicht anwenden\n"
-#~ "a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
-#~ "d - diesen und alle weiteren Patch-Blöcke in der Datei nicht anwenden"
-
-#~ 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 - Patch-Block zum Hinspringen auswählen\n"
-#~ "/ - nach Patch-Block suchen, der gegebenem regulärem Ausdruck entspricht\n"
-#~ "j - diesen Patch-Block unbestimmt lassen, nächsten unbestimmten Patch-"
-#~ "Block anzeigen\n"
-#~ "J - diesen Patch-Block unbestimmt lassen, nächsten Patch-Block anzeigen\n"
-#~ "k - diesen Patch-Block unbestimmt lassen, vorherigen unbestimmten Patch-"
-#~ "Block anzeigen\n"
-#~ "K - diesen Patch-Block unbestimmt lassen, vorherigen Patch-Block "
-#~ "anzeigen\n"
-#~ "s - aktuellen Patch-Block in kleinere Patch-Blöcke aufteilen\n"
-#~ "e - aktuellen Patch-Block manuell editieren\n"
-#~ "? - Hilfe anzeigen\n"
-
-#~ msgid "The selected hunks do not apply to the index!\n"
-#~ msgstr ""
-#~ "Die ausgewählten Patch-Blöcke können nicht auf den Index angewendet "
-#~ "werden!\n"
-
-#, perl-format
-#~ msgid "ignoring unmerged: %s\n"
-#~ msgstr "ignoriere nicht zusammengeführte Datei: %s\n"
-
-#~ msgid "No other hunks to goto\n"
-#~ msgstr "Keine anderen Patch-Blöcke verbleibend\n"
-
-#, perl-format
-#~ msgid "Invalid number: '%s'\n"
-#~ msgstr "Ungültige Nummer: '%s'\n"
-
-#, perl-format
-#~ msgid "Sorry, only %d hunk available.\n"
-#~ msgid_plural "Sorry, only %d hunks available.\n"
-#~ msgstr[0] "Entschuldigung, nur %d Patch-Block verfügbar.\n"
-#~ msgstr[1] "Entschuldigung, nur %d Patch-Blöcke verfügbar.\n"
-
-#~ msgid "No other hunks to search\n"
-#~ msgstr "Keine anderen Patch-Blöcke zum Durchsuchen\n"
-
-#, perl-format
-#~ msgid "Malformed search regexp %s: %s\n"
-#~ msgstr "Fehlerhafter regulärer Ausdruck für Suche %s: %s\n"
-
-#~ msgid "No hunk matches the given pattern\n"
-#~ msgstr "Kein Patch-Block entspricht dem angegebenen Muster\n"
-
-#~ msgid "No previous hunk\n"
-#~ msgstr "Kein vorheriger Patch-Block\n"
-
-#~ msgid "No next hunk\n"
-#~ msgstr "Kein folgender Patch-Block\n"
-
-#~ msgid "Sorry, cannot split this hunk\n"
-#~ msgstr "Entschuldigung, kann diesen Patch-Block nicht aufteilen.\n"
-
-#, perl-format
-#~ msgid "Split into %d hunk.\n"
-#~ msgid_plural "Split into %d hunks.\n"
-#~ msgstr[0] "In %d Patch-Block aufgeteilt.\n"
-#~ msgstr[1] "In %d Patch-Blöcke aufgeteilt.\n"
-
-#~ msgid "Sorry, cannot edit this hunk\n"
-#~ msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten.\n"
-
-#~ 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        - Pfade mit Änderungen anzeigen\n"
-#~ "update        - Zustand des Arbeitsverzeichnisses den zum Commit "
-#~ "vorgemerkten Änderungen hinzufügen\n"
-#~ "revert        - zum Commit vorgemerkte Änderungen auf HEAD Version "
-#~ "zurücksetzen\n"
-#~ "patch         - Patch-Blöcke auswählen und selektiv aktualisieren\n"
-#~ "diff          - Unterschiede zwischen HEAD und Index anzeigen\n"
-#~ "add untracked - Inhalte von unversionierten Dateien zum Commit vormerken\n"
-
-#~ msgid "missing --"
-#~ msgstr "-- fehlt"
-
-#, perl-format
-#~ msgid "unknown --patch mode: %s"
-#~ msgstr "Unbekannter --patch Modus: %s"
-
-#, perl-format
-#~ msgid "invalid argument %s, expecting --"
-#~ msgstr "ungültiges Argument %s, erwarte --"
index f032441614dfecc3848cea6f314588cb7bebd797..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-03-01 01:20+0000\n"
-"PO-Revision-Date: 2023-03-02 18:44+0100\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"
@@ -739,6 +738,24 @@ msgstr "Veuillez valider vos changements avant de fusionner."
 msgid "Exiting because of unfinished merge."
 msgstr "Abandon à cause d'une fusion non terminée."
 
+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 ""
+"Des branches divergentes ne peuvent pas être gérées en avance rapide, vous "
+"devez soit :\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"ou :\n"
+"\n"
+"\tgit rebase\n"
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "Pas possible d'avancer rapidement, abandon."
 
@@ -850,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"
@@ -1199,6 +1222,10 @@ msgstr "troncature du nom de fichier .rej en %.*s.rej"
 msgid "cannot open %s"
 msgstr "impossible d'ouvrir %s"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "impossible de délier '%s'"
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Section n°%d appliquée proprement."
@@ -1390,6 +1417,12 @@ msgstr "git archive --remote <dépôt> [--exec <commande>] --list"
 msgid "cannot read '%s'"
 msgstr "impossible de lire '%s'"
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr ""
+"le spécificateur de chemin '%s' correspond à des fichiers hors du répertoire "
+"actuel"
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "le chemin '%s' ne correspond à aucun fichier"
@@ -1406,9 +1439,6 @@ msgstr "nom d'objet invalide : %s"
 msgid "not a tree object: %s"
 msgstr "objet arbre invalide : %s"
 
-msgid "current working directory is untracked"
-msgstr "l'arbre de travail actuel est non-suivi"
-
 #, c-format
 msgid "File not found: %s"
 msgstr "Fichier non trouvé : %s"
@@ -1535,6 +1565,9 @@ msgstr "fichier gitattributes trop gros ignoré '%s'"
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "blob gitattributes trop gros ignoré '%s'"
 
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "mauvais --attr-source ou GIT_ATTR_SOURCE"
+
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Contenu mal cité dans le fichier '%s' : %s"
@@ -1641,9 +1674,6 @@ msgstr[1] "Bissection : %d révisions à tester après ceci %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents et --reverse ne font pas bon ménage."
 
-msgid "cannot use --contents with final commit object name"
-msgstr "on ne peut pas utiliser --contents avec un nom d'objet commit final"
-
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse et --first-parent ensemble nécessitent la spécification d'un "
@@ -1762,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"
@@ -1827,10 +1858,6 @@ msgstr "sous-module '%s' : impossible de créer la branche '%s'"
 msgid "'%s' is already checked out at '%s'"
 msgstr "'%s' est déjà extrait dans '%s'"
 
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "la HEAD de la copie de travail %s n'est pas mise à jour"
-
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<options>] [--] <chemin>..."
 
@@ -1838,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 :"
 
@@ -2284,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"
 
@@ -2888,6 +2900,14 @@ msgstr "Impossible de supprimer la branche '%s' extraite dans '%s'"
 msgid "remote-tracking branch '%s' not found."
 msgstr "branche de suivi '%s' non trouvée."
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"branche '%s' non trouvée.\n"
+"Avez-vous oublié --remote ?"
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "branche '%s' non trouvée."
@@ -2918,6 +2938,10 @@ msgstr "La branche %s est en cours de rebasage sur %s"
 msgid "Branch %s is being bisected at %s"
 msgstr "La branche %s est en cours de bissection sur %s"
 
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "la HEAD de la copie de travail %s n'est pas mise à jour"
+
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Nom de branche invalide : '%s'"
@@ -3022,6 +3046,9 @@ msgstr "déplacer/renommer une branche et son reflog"
 msgid "move/rename a branch, even if target exists"
 msgstr "déplacer/renommer une branche, même si la cible existe"
 
+msgid "do not output a newline after empty formatted refs"
+msgstr "ne pas générer de nouvelle ligne après des réfs formatées vides"
+
 msgid "copy a branch and its reflog"
 msgstr "copier une branche et son reflog"
 
@@ -3247,13 +3274,11 @@ msgid "Created new report at '%s'.\n"
 msgstr "Nouveau rapport créé à '%s'.\n"
 
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
-"                  [--version=<version>] <file> <args-de-git-rev-list>"
+"git bundle create [-q | --quiet | --progress]\n"
+"                  [--version=<version>] <fichier> <args-de-git-rev-list>"
 
 msgid "git bundle verify [-q | --quiet] <file>"
 msgstr "git bundle verify [-q | --quiet] <fichier>"
@@ -3273,11 +3298,11 @@ msgstr "ne pas afficher la barre de progression"
 msgid "show progress meter"
 msgstr "afficher la barre de progression"
 
-msgid "show progress meter during object writing phase"
-msgstr "afficher la barre de progression durant la phase d'écrite des objets"
+msgid "historical; same as --progress"
+msgstr "option historique ; identique à --progress"
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "similaire à --all-progress quand la barre de progression est affichée"
+msgid "historical; does nothing"
+msgstr "option historique ; ne fait rien"
 
 msgid "specify bundle format version"
 msgstr "spécifier la version du format de colis"
@@ -3336,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"
@@ -3386,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"
 
@@ -4262,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"
 
@@ -4300,6 +4322,10 @@ msgstr "échec du stat de '%s'"
 msgid "%s exists and is not a directory"
 msgstr "%s existe et n'est pas un répertoire"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "'%s' est un lien symbolique, refus de cloner avec --local"
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "échec du démarrage un itérateur sur '%s'"
@@ -4715,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"
 
@@ -4774,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"
@@ -5841,122 +5870,13 @@ msgstr "git fetch --all [<options>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel ne peut pas être négatif"
 
-msgid "fetch from all remotes"
-msgstr "récupérer depuis tous les dépôts distants"
-
-msgid "set upstream for git pull/fetch"
-msgstr "définir la branche amont pour git pull/fetch"
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "ajouter à .git/FETCH_HEAD au lieu de l'écraser"
-
-msgid "use atomic transaction to update references"
-msgstr "utiliser une transaction atomique pour mettre à jour les références"
-
-msgid "path to upload pack on remote end"
-msgstr "chemin vers lequel télécharger le paquet sur le poste distant"
-
-msgid "force overwrite of local reference"
-msgstr "forcer l'écrasement de la branche locale"
-
-msgid "fetch from multiple remotes"
-msgstr "récupérer depuis plusieurs dépôts distants"
-
-msgid "fetch all tags and associated objects"
-msgstr "récupérer toutes les étiquettes et leurs objets associés"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "ne pas récupérer toutes les étiquettes (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "nombre de sous-modules récupérés en parallèle"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"modifier le spécificateur de référence pour placer les références dans refs/"
-"prefetch/"
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr ""
-"élaguer les branches de suivi distant si la branche n'existe plus dans le "
-"dépôt distant"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
-"élaguer les étiquettes locales qui ont disparu du dépôt distant et qui "
-"encombrent les étiquettes modifiées"
-
-msgid "on-demand"
-msgstr "à la demande"
-
-msgid "control recursive fetching of submodules"
-msgstr "contrôler la récupération récursive dans les sous-modules"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "écrire les références récupérées dans le fichier FETCH_HEAD"
-
-msgid "keep downloaded pack"
-msgstr "conserver le paquet téléchargé"
-
-msgid "allow updating of HEAD ref"
-msgstr "permettre la mise à jour de la référence HEAD"
-
-msgid "deepen history of shallow clone"
-msgstr "approfondir l'historique d'un clone superficiel"
-
-msgid "deepen history of shallow repository based on time"
-msgstr "approfondir l'historique d'un clone superficiel en fonction d'une date"
-
-msgid "convert to a complete repository"
-msgstr "convertir en un dépôt complet"
-
-msgid "re-fetch without negotiating common commits"
-msgstr "re-récupérer sans négocier les commits communs"
-
-msgid "prepend this to submodule path output"
-msgstr "préfixer ceci à la sortie du chemin du sous-module"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"par défaut pour la récupération récursive de sous-modules (priorité plus "
-"basse que les fichiers de config)"
-
-msgid "accept refs that update .git/shallow"
-msgstr "accepter les références qui mettent à jour .git/shallow"
-
-msgid "refmap"
-msgstr "correspondance de référence"
-
-msgid "specify fetch refmap"
-msgstr "spécifier une correspondance de référence pour la récupération"
-
-msgid "report that we have only objects reachable from this object"
-msgstr "rapporte que nous n'avons que des objets joignables depuis cet objet"
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-"ne pas récupérer le fichier paquet ; à la place, afficher les ancêtres des "
-"sommets de négociation"
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr "lancer 'maintenance --auto' après la récupération"
-
-msgid "check for forced-updates on all updated branches"
-msgstr ""
-"vérifier les mises à jour forcées (forced-updates) sur toutes les branches "
-"mises à jour"
-
-msgid "write the commit-graph after fetching"
-msgstr "écrire le graphe de commits après le rapatriement"
-
-msgid "accept refspecs from stdin"
-msgstr "lire les spécificateurs de référence depuis l'entrée standard"
-
 msgid "couldn't find remote ref HEAD"
 msgstr "impossible de trouver la référence HEAD distante"
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "Depuis %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "objet %s non trouvé"
@@ -6028,10 +5948,6 @@ msgstr ""
 "%s rejeté parce que les  mises à jour de racines superficielles ne sont pas "
 "permises"
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "Depuis %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -6123,6 +6039,119 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "Vous devez spécifier un nom d'étiquette"
 
+msgid "fetch from all remotes"
+msgstr "récupérer depuis tous les dépôts distants"
+
+msgid "set upstream for git pull/fetch"
+msgstr "définir la branche amont pour git pull/fetch"
+
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "ajouter à .git/FETCH_HEAD au lieu de l'écraser"
+
+msgid "use atomic transaction to update references"
+msgstr "utiliser une transaction atomique pour mettre à jour les références"
+
+msgid "path to upload pack on remote end"
+msgstr "chemin vers lequel télécharger le paquet sur le poste distant"
+
+msgid "force overwrite of local reference"
+msgstr "forcer l'écrasement de la branche locale"
+
+msgid "fetch from multiple remotes"
+msgstr "récupérer depuis plusieurs dépôts distants"
+
+msgid "fetch all tags and associated objects"
+msgstr "récupérer toutes les étiquettes et leurs objets associés"
+
+msgid "do not fetch all tags (--no-tags)"
+msgstr "ne pas récupérer toutes les étiquettes (--no-tags)"
+
+msgid "number of submodules fetched in parallel"
+msgstr "nombre de sous-modules récupérés en parallèle"
+
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"modifier le spécificateur de référence pour placer les références dans refs/"
+"prefetch/"
+
+msgid "prune remote-tracking branches no longer on remote"
+msgstr ""
+"élaguer les branches de suivi distant si la branche n'existe plus dans le "
+"dépôt distant"
+
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr ""
+"élaguer les étiquettes locales qui ont disparu du dépôt distant et qui "
+"encombrent les étiquettes modifiées"
+
+msgid "on-demand"
+msgstr "à la demande"
+
+msgid "control recursive fetching of submodules"
+msgstr "contrôler la récupération récursive dans les sous-modules"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "écrire les références récupérées dans le fichier FETCH_HEAD"
+
+msgid "keep downloaded pack"
+msgstr "conserver le paquet téléchargé"
+
+msgid "allow updating of HEAD ref"
+msgstr "permettre la mise à jour de la référence HEAD"
+
+msgid "deepen history of shallow clone"
+msgstr "approfondir l'historique d'un clone superficiel"
+
+msgid "deepen history of shallow repository based on time"
+msgstr "approfondir l'historique d'un clone superficiel en fonction d'une date"
+
+msgid "convert to a complete repository"
+msgstr "convertir en un dépôt complet"
+
+msgid "re-fetch without negotiating common commits"
+msgstr "re-récupérer sans négocier les commits communs"
+
+msgid "prepend this to submodule path output"
+msgstr "préfixer ceci à la sortie du chemin du sous-module"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"par défaut pour la récupération récursive de sous-modules (priorité plus "
+"basse que les fichiers de config)"
+
+msgid "accept refs that update .git/shallow"
+msgstr "accepter les références qui mettent à jour .git/shallow"
+
+msgid "refmap"
+msgstr "correspondance de référence"
+
+msgid "specify fetch refmap"
+msgstr "spécifier une correspondance de référence pour la récupération"
+
+msgid "report that we have only objects reachable from this object"
+msgstr "rapporte que nous n'avons que des objets joignables depuis cet objet"
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+"ne pas récupérer le fichier paquet ; à la place, afficher les ancêtres des "
+"sommets de négociation"
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr "lancer 'maintenance --auto' après la récupération"
+
+msgid "check for forced-updates on all updated branches"
+msgstr ""
+"vérifier les mises à jour forcées (forced-updates) sur toutes les branches "
+"mises à jour"
+
+msgid "write the commit-graph after fetching"
+msgstr "écrire le graphe de commits après le rapatriement"
+
+msgid "accept refspecs from stdin"
+msgstr "lire les spécificateurs de référence depuis l'entrée standard"
+
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only nécessite au moins un --negotiation-tip=*"
 
@@ -6238,6 +6267,12 @@ msgstr "afficher seulement les références qui contiennent le commit"
 msgid "print only refs which don't contain the commit"
 msgstr "afficher seulement les références qui ne contiennent pas le commit"
 
+msgid "read reference patterns from stdin"
+msgstr "lire les motifs de références depuis l'entrée standard"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "arguments inconnus fournis avec l'option --stdin"
+
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<config> [--] <arguments>"
 
@@ -6250,6 +6285,10 @@ msgstr "clé de config qui stocke la liste des chemins de dépôts"
 msgid "missing --config=<config>"
 msgstr "--config=<config> manquant"
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "config incorrecte --config=%s"
+
 msgid "unknown"
 msgstr "inconnu"
 
@@ -6396,19 +6435,28 @@ msgstr "%s : la HEAD détachée ne pointe sur rien"
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "note : %s pointe sur une branche non-née (%s)"
 
-msgid "Checking cache tree"
-msgstr "Vérification de l'arbre cache"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Vérification de l'arbre cache de %s"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s : pointer sha1 invalide dans l'arbre de cache"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s : pointer sha1 invalide dans l'arbre de cache de %s"
 
 msgid "non-tree in cache-tree"
 msgstr "non-arbre dans l'arbre de cache"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s : pointeur sha1 invalide dans resolve-undo"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s : pointeur sha1 invalide dans resolve-undo de %s"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "impossible de charger le rev-index pour le paquet '%s'"
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "rev-index invalide pour le paquet '%s'"
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -7404,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"
@@ -7922,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 '('"
@@ -8069,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 '('"
@@ -8815,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>]"
@@ -8962,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 "
@@ -9321,6 +9311,12 @@ msgstr "version d'index non supportée %s"
 msgid "bad index version '%s'"
 msgstr "mauvaise version d'index '%s'"
 
+msgid "show progress meter during object writing phase"
+msgstr "afficher la barre de progression durant la phase d'écrite des objets"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "similaire à --all-progress quand la barre de progression est affichée"
+
 msgid "<version>[,<offset>]"
 msgstr "<version>[,<décalage>]"
 
@@ -9518,8 +9514,14 @@ msgstr ""
 "sur la ligne de commande pour nous avertir par\n"
 "un courriel à <git@vger.kernel.org>. Merci.\n"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+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] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <motif>] [--exclude <motif>]"
 
 msgid "pack everything"
 msgstr "empaqueter tout"
@@ -9527,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]"
 
@@ -9584,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."
@@ -9694,8 +9708,8 @@ msgstr ""
 msgid "pull with rebase"
 msgstr "tirer avec un rebasage"
 
-msgid "please commit or stash them."
-msgstr "veuillez les valider ou les remiser."
+msgid "Please commit or stash them."
+msgstr "Veuillez les valider ou les remiser."
 
 #, c-format
 msgid ""
@@ -9854,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."
 
@@ -9914,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"
@@ -9946,8 +9960,8 @@ msgstr "valeur invalide pour '%s'"
 msgid "repository"
 msgstr "dépôt"
 
-msgid "push all refs"
-msgstr "pousser toutes les références"
+msgid "push all branches"
+msgstr "pousser toutes les branches"
 
 msgid "mirror all refs"
 msgstr "refléter toutes les références"
@@ -9955,9 +9969,10 @@ msgstr "refléter toutes les références"
 msgid "delete refs"
 msgstr "supprimer les références"
 
-msgid "push tags (can't be used with --all or --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
 msgstr ""
-"pousser les étiquettes (ne peut pas être utilisé avec --all ou --mirror)"
+"pousser les étiquettes (ne peut pas être utilisé avec --all, --branches ou --"
+"mirror)"
 
 msgid "force updates"
 msgstr "forcer les mises à jour"
@@ -10224,6 +10239,10 @@ msgstr ""
 "\n"
 "Résultat, git ne peut pas les rebaser."
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Mode de rebase-merges inconnu : %s"
+
 #, c-format
 msgid "could not switch to %s"
 msgstr "impossible de basculer vers %s"
@@ -10240,6 +10259,15 @@ msgstr ""
 "type vide non connu '%s' ; les valeurs valides sont \"drop\" (abandonner), "
 "\"keep\" (garder) et \"ask\" (demander)."
 
+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 avec un argument chaîne vide est obsolète et cessera de "
+"fonctionner dans une version future de Git. Utilisez à la place --rebase-"
+"merges sans argument, qui a le même effet."
+
 #, c-format
 msgid ""
 "%s\n"
@@ -10460,20 +10488,23 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "l'option `C' attend un valeur numérique"
 
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Mode inconnu : %s"
-
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy requiert --merge ou --interactive"
 
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"les options d'application sont incompatibles avec rebase.autosquash. "
+"les options d'application sont incompatibles avec rebase.autoSquash. "
 "Considérez l'ajout de --no-autosquash"
 
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"les options d'application sont incompatibles avec rebase.rebaseMerges. "
+"Considérez l'ajout de --no-rebase-merges"
+
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
@@ -10518,9 +10549,6 @@ msgstr "'%s': exactement une base de fusion nécessaire"
 msgid "Does not point to a valid commit '%s'"
 msgstr "Ne pointe pas sur une validation valide : '%s'"
 
-msgid "Please commit or stash them."
-msgstr "Veuillez les valider ou les remiser."
-
 msgid "HEAD is up to date."
 msgstr "HEAD est à jour."
 
@@ -10780,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"
@@ -11197,8 +11226,8 @@ msgstr ""
 msgid "approxidate"
 msgstr "date approximative"
 
-msgid "with -C, expire objects older than this"
-msgstr "avec -C, faire expirer les objets plus vieux que celui-ci"
+msgid "with --cruft, expire objects older than this"
+msgstr "avec --cruft, faire expirer les objets plus vieux que celui-ci"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "supprimer les paquets redondants et lancer git-prune-packed"
@@ -11871,6 +11900,9 @@ msgstr ""
 msgid "remote name"
 msgstr "nom distant"
 
+msgid "push all refs"
+msgstr "pousser toutes les références"
+
 msgid "use stateless RPC protocol"
 msgstr "utiliser un protocole RPC sans état"
 
@@ -12081,9 +12113,11 @@ msgstr ""
 "local"
 
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 
 msgid "this worktree is not sparse"
 msgstr "cet arbre de travail n'est pas clairsemé"
@@ -12213,6 +12247,24 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr "erreur lors du rafraîchissement du répertoire de travail"
 
+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 <fichier>]"
+
+msgid "terminate input and output files by a NUL character"
+msgstr "terminer les fichiers en entrée et en sortie par un caractère NUL"
+
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
+"quand utilisé avec --rules-file, interpréter les motifs comme des motifs en "
+"mode cone"
+
+msgid "use patterns in <file> instead of the current ones."
+msgstr "utiliser les motifs dans <fichier> plutôt que les actuels."
+
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [<options-de-log>]"
 
@@ -12419,7 +12471,7 @@ msgid "stash staged changes only"
 msgstr "remiser seulement les modifications indexées"
 
 msgid "stash in patch mode"
-msgstr "remiser une mode rustine"
+msgstr "remiser en mode rustine"
 
 msgid "quiet mode"
 msgstr "mode silencieux"
@@ -12745,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"
@@ -13508,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]]"
@@ -13534,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"
@@ -13605,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 "
@@ -13620,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"
 
@@ -13639,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"
 
@@ -13876,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"
 
@@ -14111,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"
@@ -14535,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 ""
@@ -14626,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"
 
@@ -14658,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 ""
@@ -14713,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 !"
@@ -15146,8 +15291,8 @@ msgstr "longueur d'abbrev hors plage : %d"
 msgid "bad zlib compression level %d"
 msgstr "niveau de compression zlib incorrect %d"
 
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar ne devrait être qu'un unique caractère"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar ne devrait être qu'un unique caractère ASCII"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15261,6 +15406,12 @@ msgstr "impossible de régler '%s' à '%s'"
 msgid "invalid section name: %s"
 msgstr "nom de section invalide : %s"
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr ""
+"refus de travailler avec des lignes trop longues dans '%s' à la ligne "
+"%<PRIuMAX>"
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr "valeur manquante pour '%s'"
@@ -15675,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>"
 
@@ -15734,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 ""
@@ -15752,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"
@@ -15950,6 +16112,9 @@ msgstr "préfixer toutes les lignes en sortie avec la chaîne indiquée"
 msgid "do not show any source or destination prefix"
 msgstr "n'afficher aucun préfixe, ni de source, ni de destination"
 
+msgid "use default prefixes a/ and b/"
+msgstr "utiliser les préfixes par défaut a/ et b/"
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
 "afficher le contexte entre les sections à concurrence du nombre de ligne "
@@ -16271,6 +16436,14 @@ msgstr ""
 "suggestion : en attente de la fermeture du fichier par votre éditeur de "
 "texte…%c"
 
+#, c-format
+msgid "could not write to '%s'"
+msgstr "impossible d'écrire dans '%s'"
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr "impossible d'éditer '%s'"
+
 msgid "Filtering content"
 msgstr "Filtrage du contenu"
 
@@ -16569,6 +16742,10 @@ msgstr "-c requiert une chaîne de configuration\n"
 msgid "no config key given for --config-env\n"
 msgstr "aucune clé de configuration fournie pour --config-env\n"
 
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "aucune source d'attribut fournie pour --attr-source\n"
+
 #, c-format
 msgid "unknown option: %s\n"
 msgstr "option inconnue : %s\n"
@@ -18264,6 +18441,10 @@ msgstr "impossible de trouver '%s' dans le paquet '%s' à l'offset %<PRIuMAX>"
 msgid "unable to get disk usage of '%s'"
 msgstr "impossible de récupérer l'utilisation du disque de '%s'"
 
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "le fichier bitmap '%s' a une somme de contrôle invalide"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "le fichier de mtimes %s est trop petit"
@@ -18304,6 +18485,13 @@ msgstr "le fichier d'index inverse %s a une version non gérée %<PRIu32>"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "le fichier d'index inverse %s a un id d'empreinte non géré %<PRIu32>"
 
+msgid "invalid checksum"
+msgstr "somme de contrôle invalide"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "position de rev-index invalide à %<PRIu64> : %<PRIu32> != %<PRIu32>"
+
 msgid "cannot both write and verify reverse index"
 msgstr "impossible de lire et vérifier à la fois l'index inverse"
 
@@ -18659,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)"
@@ -18811,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"
@@ -19013,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)"
@@ -19037,6 +19256,10 @@ msgstr "argument %%(%s) non reconnu : %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "valeur positive attendue avec l'atome %%(align)"
 
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "format attendu : %%(ahead-behind:<commit-esque>)"
+
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "nom de champ malformé %.*s"
@@ -19083,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)"
@@ -19144,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"
@@ -19597,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'"
@@ -19671,10 +19901,6 @@ msgstr "échec de la mise à jour de l'état en conflit dans '%s'"
 msgid "no remembered resolution for '%s'"
 msgstr "aucune résolution enregistrée pour '%s'"
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "impossible de délier '%s'"
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "Pré-image mise à jour pour '%s'"
@@ -19716,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"
 
@@ -20013,10 +20243,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "impossible de verrouiller '%s'"
 
-#, c-format
-msgid "could not write to '%s'"
-msgstr "impossible d'écrire dans '%s'"
-
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "impossible d'écrire la fin de ligne dans '%s'"
@@ -20382,9 +20608,6 @@ msgstr "essayez \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgid "could not create sequencer directory '%s'"
 msgstr "impossible de créer le répertoire de séquenceur '%s'"
 
-msgid "could not lock HEAD"
-msgstr "impossible de verrouiller HEAD"
-
 msgid "no cherry-pick or revert in progress"
 msgstr "aucun picorage ou retour en cours"
 
@@ -20480,20 +20703,20 @@ msgstr ""
 "git rebase --continue\n"
 "\n"
 
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "et a mis à jour l'index ou l'arbre de travail\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "et a mis à jour l'index ou l'arbre de travail.\n"
 
 #, 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 ""
 "l'exécution a réussi : %s\n"
-"mais a laissé des modifications dans l'index ou la copie de travail\n"
+"mais a laissé des modifications dans l'index ou la copie de travail.\n"
 "Validez ou remisez vos modification, puis lancez\n"
 "\n"
 "  git rebase --continue\n"
@@ -20885,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)"
@@ -20936,10 +21230,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u octet/s"
 msgstr[1] "%u octets/s"
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr "impossible d'éditer '%s'"
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "nom de sous-module suspicieux %s ignoré"
@@ -22698,13 +22988,17 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) Impossible d'exécuter '%s'"
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Ajout de %s : %s depuis : '%s'\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Sortie malformée depuis '%s'"
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) échec de la fermeture du pipe vers '%s'"
 
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) Ajout de %s : %s depuis : '%s'\n"
+
 msgid "cannot send message as 7bit"
 msgstr "impossible d'envoyer un message comme 7bit"
 
@@ -22741,3 +23035,42 @@ msgstr "%s sauté avec un suffix de sauvegarde '%s'.\n"
 #, perl-format
 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"
+
+#~ msgid "cannot use --contents with final commit object name"
+#~ msgstr "on ne peut pas utiliser --contents avec un nom d'objet commit final"
+
+#~ msgid "please commit or stash them."
+#~ msgstr "veuillez les valider ou les remiser."
+
+#, c-format
+#~ msgid "Unknown mode: %s"
+#~ msgstr "Mode inconnu : %s"
+
+#~ msgid "could not lock HEAD"
+#~ msgstr "impossible de verrouiller HEAD"
index e468b6d9b82445b1eaea1dfe238d8920c0f9d5b0..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-03-02 15:18+0700\n"
-"PO-Revision-Date: 2023-03-02 17:52+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"
@@ -792,6 +792,25 @@ msgstr "Mohon komit perubahan Anda sebelum menggabungkan."
 msgid "Exiting because of unfinished merge."
 msgstr "Keluar karena penggabungan belum selesai."
 
+#: advice.c
+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 ""
+"Cabang yang menyebar tidak dapat dimajucepatkan, Anda perlu salah satu "
+"dari:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"atau:\n"
+"\n"
+"\tgit rebase\n"
+
 #: advice.c
 msgid "Not possible to fast-forward, aborting."
 msgstr "Tidak mungkin untuk maju cepat, batalkan."
@@ -922,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"
@@ -1339,6 +1366,11 @@ msgstr "memotong nama berkas .rej ke %.*s.rej"
 msgid "cannot open %s"
 msgstr "tidak dapat membuka %s"
 
+#: apply.c rerere.c
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "tidak dapat batal taut '%s'"
+
 #: apply.c
 #, c-format
 msgid "Hunk #%d applied cleanly."
@@ -1579,6 +1611,11 @@ msgstr "git archive --remote <repo> [--exec <perintah>] --list"
 msgid "cannot read '%s'"
 msgstr "tidak dapat membaca '%s'"
 
+#: archive.c
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "spek jalur '%s' mencocoki berkas di luar direktori saat ini"
+
 #: archive.c builtin/add.c builtin/rm.c
 #, c-format
 msgid "pathspec '%s' did not match any files"
@@ -1599,10 +1636,6 @@ msgstr "bukan nama objek valid: %s"
 msgid "not a tree object: %s"
 msgstr "bukan objek pohon: %s"
 
-#: archive.c
-msgid "current working directory is untracked"
-msgstr "direktori kerja saat ini tak terlacak"
-
 #: archive.c
 #, c-format
 msgid "File not found: %s"
@@ -1771,6 +1804,10 @@ msgstr "mengabaikan berkas gitattributes yang terlalu besar '%s'"
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "mengabaikan blob gitattributes '%s' yang terlalu besar"
 
+#: attr.c
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "--attr-source atau GIT_ATTR_SOURCE jelek"
+
 #: bisect.c
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
@@ -1894,18 +1931,14 @@ msgstr[1] "Membagi dua: %d revisi tersisa untuk diuji setelah ini %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents dan --reverse tidak dapat dipadu dengan baik."
 
-#: blame.c
-msgid "cannot use --contents with final commit object name"
-msgstr "tidak dapat menggunakan --contents dengan nama objek komit final"
-
 #: blame.c
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse dan --first-parent bersama-sama butuh komit terbaru yang disebutkan"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c ref-filter.c
-#: remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c remote.c
+#: sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "persiapan jalan revisi gagal"
 
@@ -2037,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
@@ -2111,11 +2146,6 @@ msgstr "submodul '%s': tidak dapat membuat cabang '%s'"
 msgid "'%s' is already checked out at '%s'"
 msgstr "'%s' sudah di-checkout pada '%s'"
 
-#: branch.c
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "HEAD dari pohon kerja %s tidak diperbarui"
-
 #: builtin/add.c
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<opsi>] [--] <pathspec>..."
@@ -2125,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:"
@@ -2386,7 +2402,7 @@ msgstr "fseek gagal"
 msgid "could not open '%s' for reading"
 msgstr "tidak dapat membuka '%s' untuk dibaca"
 
-#: builtin/am.c builtin/rebase.c sequencer.c strbuf.c wrapper.c
+#: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "tidak dapat membuka '%s' untuk ditulis"
@@ -2684,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"
@@ -3429,6 +3440,15 @@ msgstr "Tidak dapat menghapus cabang '%s' yang ter-checkout pada '%s'"
 msgid "remote-tracking branch '%s' not found."
 msgstr "cabang pelacak remote '%s' tidak ditemukan."
 
+#: builtin/branch.c
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"cabang '%s' tidak ditemukan.\n"
+"Mungkin anda lupa menambahkan --remote?"
+
 #: builtin/branch.c
 #, c-format
 msgid "branch '%s' not found."
@@ -3467,6 +3487,11 @@ msgstr "Cabang %s sedang didasarkan ulang pada %s"
 msgid "Branch %s is being bisected at %s"
 msgstr "Cabang %s sedang dibagi dua pada %s"
 
+#: builtin/branch.c
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "HEAD dari pohon kerja %s tidak diperbarui"
+
 #: builtin/branch.c
 #, c-format
 msgid "Invalid branch name: '%s'"
@@ -3596,6 +3621,10 @@ msgstr "pindah/ganti nama cabang dan reflog-nya"
 msgid "move/rename a branch, even if target exists"
 msgstr "pindah/ganti nama cabang, walaupun target ada"
 
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
+msgid "do not output a newline after empty formatted refs"
+msgstr "jangan keluarkan baris baru setelah referensi terformat kosong"
+
 #: builtin/branch.c
 msgid "copy a branch and its reflog"
 msgstr "salin cabang dan reflog-nya"
@@ -3872,12 +3901,10 @@ msgstr "Laporan baru dibuat pada '%s'.\n"
 
 #: builtin/bundle.c
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [-all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<versi>] <berkas> <argumen git-rev-list>"
 
 #: builtin/bundle.c
@@ -3904,13 +3931,13 @@ msgstr "jangan perlihatkan meteran perkembangan"
 msgid "show progress meter"
 msgstr "perlihatkan meteran perkembangan"
 
-#: builtin/bundle.c builtin/pack-objects.c
-msgid "show progress meter during object writing phase"
-msgstr "perlihatkan meteran perkembangan saat fase penulisan objek"
+#: builtin/bundle.c
+msgid "historical; same as --progress"
+msgstr "opsi bersejarah; sama dengan --progress"
 
-#: builtin/bundle.c builtin/pack-objects.c
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "sama seperti --all-progress ketika meteran perkembangan diperlihatkan"
+#: builtin/bundle.c
+msgid "historical; does nothing"
+msgstr "opsi bersejarah: tidak apa-apa"
 
 #: builtin/bundle.c
 msgid "specify bundle format version"
@@ -3986,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"
@@ -4050,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"
@@ -4588,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 ""
@@ -4605,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 ""
@@ -4623,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"
@@ -4963,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"
 
@@ -5135,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"
@@ -5179,6 +5203,11 @@ msgstr "gagal men-stat '%s'"
 msgid "%s exists and is not a directory"
 msgstr "%s ada dan bukan direktori"
 
+#: builtin/clone.c
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "'%s' tautan simbolik, menolak mengkloning dengan --local"
+
 #: builtin/clone.c
 #, c-format
 msgid "failed to start iterator over '%s'"
@@ -5685,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"
@@ -5762,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
@@ -5983,7 +6016,7 @@ msgstr "hitung nilai didepan/dibelakang penuh"
 msgid "version"
 msgstr "versi"
 
-#: builtin/commit.c builtin/push.c builtin/worktree.c
+#: builtin/commit.c builtin/fetch.c builtin/push.c builtin/worktree.c
 msgid "machine-readable output"
 msgstr "keluaran yang dapat dibaca mesin"
 
@@ -7078,150 +7111,15 @@ msgstr "git fetch --all [<opsi>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel tidak dapat bernilai negatif"
 
-#: builtin/fetch.c builtin/pull.c
-msgid "fetch from all remotes"
-msgstr "ambil dari semua remote"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "set upstream for git pull/fetch"
-msgstr "setel hulu untuk git pull/fetch"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "tambah ke .git/FETCH_HEAD daripada timpa"
-
-#: builtin/fetch.c
-msgid "use atomic transaction to update references"
-msgstr "gunakan transaksi atomik untuk memperbarui referensi"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "path to upload pack on remote end"
-msgstr "jalur ke paket unggah pada sisi remote"
-
-#: builtin/fetch.c
-msgid "force overwrite of local reference"
-msgstr "paksa timpa referensi lokal"
-
-#: builtin/fetch.c
-msgid "fetch from multiple remotes"
-msgstr "ambil dari banyak remote"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "fetch all tags and associated objects"
-msgstr "ambil semua tag dan objek yang bersesuaian"
-
-#: builtin/fetch.c
-msgid "do not fetch all tags (--no-tags)"
-msgstr "jangan ambil semua tag (--no-tags)"
-
-#: builtin/fetch.c
-msgid "number of submodules fetched in parallel"
-msgstr "jumlah submodul yang diambil secara bersamaan"
-
-#: builtin/fetch.c
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"modifikasi spek referensi untuk tempatkan semua referensi di dalam refs/"
-"prefetch/"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "prune remote-tracking branches no longer on remote"
-msgstr "buang cabang pelacak remote yang tidak ada pada remote"
-
-#: builtin/fetch.c
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr "buang tag lokal yang tidak ada pada remote dan klob tag yang berubah"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "on-demand"
-msgstr "sesuai permintaan"
-
-#: builtin/fetch.c
-msgid "control recursive fetching of submodules"
-msgstr "kontrol pengambilan submodul rekursif"
-
-#: builtin/fetch.c
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "tulis referensi yang diambil ke berkas FETCH_HEAD"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "keep downloaded pack"
-msgstr "simpan paket yang diunduh"
-
-#: builtin/fetch.c
-msgid "allow updating of HEAD ref"
-msgstr "bolehkan perbarui referensi HEAD"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow clone"
-msgstr "perdalam riwayat klon dangkal"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow repository based on time"
-msgstr "perdalam riwayat repositori dangkal berdasarkan waktu"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "convert to a complete repository"
-msgstr "ubah ke repositori penuh"
-
-#: builtin/fetch.c
-msgid "re-fetch without negotiating common commits"
-msgstr "ambil ulang tanpa menegosiasikan komit yang sama"
-
-#: builtin/fetch.c
-msgid "prepend this to submodule path output"
-msgstr "tambahkan ini ke jalur keluaran submodul"
-
-#: builtin/fetch.c
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"default untuk ambil submodul secara rekursif (prioritas lebih rendah "
-"dariberkas konfigurasi)"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "accept refs that update .git/shallow"
-msgstr "terima referensi yang memperbarui .git/shallow"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "refmap"
-msgstr "peta referensi"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "specify fetch refmap"
-msgstr "sebutkan ambil peta referensi"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "report that we have only objects reachable from this object"
-msgstr ""
-"laporkan bahwa kami hanya punya object yang bisa dicapai dari objek ini"
-
-#: builtin/fetch.c
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-"jangan ambil berkas pak; sebagai gantinya cetak leluhur dari ujung negosiasi"
-
-#: builtin/fetch.c
-msgid "run 'maintenance --auto' after fetching"
-msgstr "lakukan 'maintenance --auto' setelah pengambilan"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "check for forced-updates on all updated branches"
-msgstr "periksa pembaruan terpaksa pada semua cabang"
-
-#: builtin/fetch.c
-msgid "write the commit-graph after fetching"
-msgstr "tulis grafik komit setelah pengambilan"
-
-#: builtin/fetch.c
-msgid "accept refspecs from stdin"
-msgstr "terima spek referensi dari masukan standar"
-
 #: builtin/fetch.c
 msgid "couldn't find remote ref HEAD"
 msgstr "tidak dapat menemukan referensi remote HEAD"
 
+#: builtin/fetch.c
+#, c-format
+msgid "From %.*s\n"
+msgstr "Dari %.*s\n"
+
 #: builtin/fetch.c
 #, c-format
 msgid "object %s not found"
@@ -7311,11 +7209,6 @@ msgstr "%s tidak mengirim semua objek yang diperlukan\n"
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr "tolak %s karena akar dangkal tidak diperkenankan untuk diperbarui"
 
-#: builtin/fetch.c
-#, c-format
-msgid "From %.*s\n"
-msgstr "Dari %.*s\n"
-
 #: builtin/fetch.c
 #, c-format
 msgid ""
@@ -7386,47 +7279,187 @@ msgid "not setting upstream for a remote remote-tracking branch"
 msgstr "tidak setel hulu untuk cabang remote pelacak remote"
 
 #: builtin/fetch.c
-msgid "not setting upstream for a remote tag"
-msgstr "tidak setel hulu untuk tag remote"
+msgid "not setting upstream for a remote tag"
+msgstr "tidak setel hulu untuk tag remote"
+
+#: builtin/fetch.c
+msgid "unknown branch type"
+msgstr "tipe cabang tidak diketahui"
+
+#: builtin/fetch.c
+msgid ""
+"no source branch found;\n"
+"you need to specify exactly one branch with the --set-upstream option"
+msgstr ""
+"cabang sumber tidak ditemukan;\n"
+"Anda harus sebutkan tepat satu cabang dengan opsi --set-upstream."
+
+#: builtin/fetch.c
+#, c-format
+msgid "Fetching %s\n"
+msgstr "Mengambil %s\n"
+
+#: builtin/fetch.c
+#, c-format
+msgid "could not fetch %s"
+msgstr "tidak dapat mengambil %s"
+
+#: builtin/fetch.c
+#, c-format
+msgid "could not fetch '%s' (exit code: %d)\n"
+msgstr "tidak dapat mengambil '%s' (kode keluar: %d)\n"
+
+#: builtin/fetch.c
+msgid ""
+"no remote repository specified; please specify either a URL or a\n"
+"remote name from which new revisions should be fetched"
+msgstr ""
+"repositori remote tidak disebutkan; mohon sebutkan baik URL atau nama\n"
+"remote yang mana revisi baru sebaiknya diambil"
+
+#: builtin/fetch.c
+msgid "you need to specify a tag name"
+msgstr "Anda perlu sebutkan sebuah nama tag"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "fetch from all remotes"
+msgstr "ambil dari semua remote"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "set upstream for git pull/fetch"
+msgstr "setel hulu untuk git pull/fetch"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "tambah ke .git/FETCH_HEAD daripada timpa"
+
+#: builtin/fetch.c
+msgid "use atomic transaction to update references"
+msgstr "gunakan transaksi atomik untuk memperbarui referensi"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "path to upload pack on remote end"
+msgstr "jalur ke paket unggah pada sisi remote"
+
+#: builtin/fetch.c
+msgid "force overwrite of local reference"
+msgstr "paksa timpa referensi lokal"
+
+#: builtin/fetch.c
+msgid "fetch from multiple remotes"
+msgstr "ambil dari banyak remote"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "fetch all tags and associated objects"
+msgstr "ambil semua tag dan objek yang bersesuaian"
+
+#: builtin/fetch.c
+msgid "do not fetch all tags (--no-tags)"
+msgstr "jangan ambil semua tag (--no-tags)"
+
+#: builtin/fetch.c
+msgid "number of submodules fetched in parallel"
+msgstr "jumlah submodul yang diambil secara bersamaan"
+
+#: builtin/fetch.c
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"modifikasi spek referensi untuk tempatkan semua referensi di dalam refs/"
+"prefetch/"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "buang cabang pelacak remote yang tidak ada pada remote"
+
+#: builtin/fetch.c
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr "buang tag lokal yang tidak ada pada remote dan klob tag yang berubah"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "on-demand"
+msgstr "sesuai permintaan"
+
+#: builtin/fetch.c
+msgid "control recursive fetching of submodules"
+msgstr "kontrol pengambilan submodul rekursif"
+
+#: builtin/fetch.c
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "tulis referensi yang diambil ke berkas FETCH_HEAD"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "keep downloaded pack"
+msgstr "simpan paket yang diunduh"
+
+#: builtin/fetch.c
+msgid "allow updating of HEAD ref"
+msgstr "bolehkan perbarui referensi HEAD"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow clone"
+msgstr "perdalam riwayat klon dangkal"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow repository based on time"
+msgstr "perdalam riwayat repositori dangkal berdasarkan waktu"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "convert to a complete repository"
+msgstr "ubah ke repositori penuh"
+
+#: builtin/fetch.c
+msgid "re-fetch without negotiating common commits"
+msgstr "ambil ulang tanpa menegosiasikan komit yang sama"
 
 #: builtin/fetch.c
-msgid "unknown branch type"
-msgstr "tipe cabang tidak diketahui"
+msgid "prepend this to submodule path output"
+msgstr "tambahkan ini ke jalur keluaran submodul"
 
 #: builtin/fetch.c
 msgid ""
-"no source branch found;\n"
-"you need to specify exactly one branch with the --set-upstream option"
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
 msgstr ""
-"cabang sumber tidak ditemukan;\n"
-"Anda harus sebutkan tepat satu cabang dengan opsi --set-upstream."
+"default untuk ambil submodul secara rekursif (prioritas lebih rendah "
+"dariberkas konfigurasi)"
 
-#: builtin/fetch.c
-#, c-format
-msgid "Fetching %s\n"
-msgstr "Mengambil %s\n"
+#: builtin/fetch.c builtin/pull.c
+msgid "accept refs that update .git/shallow"
+msgstr "terima referensi yang memperbarui .git/shallow"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "refmap"
+msgstr "peta referensi"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "specify fetch refmap"
+msgstr "sebutkan ambil peta referensi"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "report that we have only objects reachable from this object"
+msgstr ""
+"laporkan bahwa kami hanya punya object yang bisa dicapai dari objek ini"
 
 #: builtin/fetch.c
-#, c-format
-msgid "could not fetch %s"
-msgstr "tidak dapat mengambil %s"
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+"jangan ambil berkas pak; sebagai gantinya cetak leluhur dari ujung negosiasi"
 
 #: builtin/fetch.c
-#, c-format
-msgid "could not fetch '%s' (exit code: %d)\n"
-msgstr "tidak dapat mengambil '%s' (kode keluar: %d)\n"
+msgid "run 'maintenance --auto' after fetching"
+msgstr "lakukan 'maintenance --auto' setelah pengambilan"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "check for forced-updates on all updated branches"
+msgstr "periksa pembaruan terpaksa pada semua cabang"
 
 #: builtin/fetch.c
-msgid ""
-"no remote repository specified; please specify either a URL or a\n"
-"remote name from which new revisions should be fetched"
-msgstr ""
-"repositori remote tidak disebutkan; mohon sebutkan baik URL atau nama\n"
-"remote yang mana revisi baru sebaiknya diambil"
+msgid "write the commit-graph after fetching"
+msgstr "tulis grafik komit setelah pengambilan"
 
 #: builtin/fetch.c
-msgid "you need to specify a tag name"
-msgstr "Anda perlu sebutkan sebuah nama tag"
+msgid "accept refspecs from stdin"
+msgstr "terima spek referensi dari masukan standar"
 
 #: builtin/fetch.c
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
@@ -7576,6 +7609,14 @@ msgstr "hanya cetak referensi yang berisi komit"
 msgid "print only refs which don't contain the commit"
 msgstr "hanya cetak referensi yang tidak berisi komit"
 
+#: builtin/for-each-ref.c
+msgid "read reference patterns from stdin"
+msgstr "baca pola referensi dari masukan standar"
+
+#: builtin/for-each-ref.c
+msgid "unknown arguments supplied with --stdin"
+msgstr "argumen tidak dikenal diberikan dengan --stdin"
+
 #: builtin/for-each-repo.c
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<konfigurasi> [--] <argumen perintah>"
@@ -7592,6 +7633,11 @@ msgstr "kunci konfigurasi yang menampung daftar jalur repositori"
 msgid "missing --config=<config>"
 msgstr "kehilangan --config=<config>"
 
+#: builtin/for-each-repo.c
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "dapat konfigurasi jelek --config=%s"
+
 #: builtin/fsck.c
 msgid "unknown"
 msgstr "tidak dikenal"
@@ -7777,13 +7823,14 @@ msgid "notice: %s points to an unborn branch (%s)"
 msgstr "catatan: %s menunjuk ke cabang yang belum lahir (%s)"
 
 #: builtin/fsck.c
-msgid "Checking cache tree"
-msgstr "Memeriksa pohon tembolok"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Memeriksa pohon tembolok %s"
 
 #: builtin/fsck.c
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s: penunjuk sha1 tidak valid pada pohon tembolok"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: penunjuk sha1 tidak valid pada pohon tembolok %s"
 
 #: builtin/fsck.c
 msgid "non-tree in cache-tree"
@@ -7791,8 +7838,18 @@ msgstr "bukan pohon pada pohon tembolok"
 
 #: builtin/fsck.c
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s: penunjuk sha1 tidak valid di resolve-undo"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: penunjuk sha1 tidak valid di resolve-undo %s"
+
+#: builtin/fsck.c
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "tidak dapat memuat indeks balik untuk pak '%s'"
+
+#: builtin/fsck.c
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "indeks balik tidak valid untuk pak '%s'"
 
 #: builtin/fsck.c
 msgid ""
@@ -8000,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'"
@@ -9024,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'"
@@ -9041,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"
@@ -9690,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 '('"
@@ -9877,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 '('"
@@ -10422,7 +10390,7 @@ msgstr "Tidak ada cabang pelacak remote untuk %s dari %s"
 msgid "Bad value '%s' in environment '%s'"
 msgstr "Nilai jelek '%s' dalam lingkungan '%s'"
 
-#: builtin/merge.c read-cache.c strbuf.c wrapper.c
+#: builtin/merge.c editor.c read-cache.c wrapper.c
 #, c-format
 msgid "could not close '%s'"
 msgstr "tidak dapat menutup '%s'"
@@ -10819,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>"
@@ -10832,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>]"
@@ -11006,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 ""
@@ -11278,7 +11262,7 @@ msgstr "gagal menulis indeks bitmap"
 msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
 msgstr "%<PRIu32> objek ditulish ketika mengharapkan %<PRIu32>"
 
-#: builtin/pack-objects.c
+#: builtin/pack-objects.c builtin/repack.c
 msgid "disabling bitmap writing, as some objects are not being packed"
 msgstr "menonaktifkan penulisan bitmap, saat beberapa objek tidak sedang dipak"
 
@@ -11446,6 +11430,14 @@ msgstr "versi indeks tidak didukung %s"
 msgid "bad index version '%s'"
 msgstr "versi indeks jelek '%s'"
 
+#: builtin/pack-objects.c
+msgid "show progress meter during object writing phase"
+msgstr "perlihatkan meteran perkembangan saat fase penulisan objek"
+
+#: builtin/pack-objects.c
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "sama seperti --all-progress ketika meteran perkembangan diperlihatkan"
+
 #: builtin/pack-objects.c
 msgid "<version>[,<offset>]"
 msgstr "<versi>[,<offset>]"
@@ -11693,9 +11685,16 @@ msgstr ""
 "Anda masih menggunakannya dengan mengirimkan surel ke\n"
 "<git@vger.kernel.org>. Terima kasih.\n"
 
+#: builtin/pack-redundant.c
+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"
@@ -11705,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]"
@@ -11781,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 "
@@ -11909,9 +11924,9 @@ msgstr ""
 msgid "pull with rebase"
 msgstr "tarik dengan pendasaran ulang"
 
-#: builtin/pull.c
-msgid "please commit or stash them."
-msgstr "mohon komit atau stase."
+#: builtin/pull.c builtin/rebase.c
+msgid "Please commit or stash them."
+msgstr "Mohon komit atau stase."
 
 #: builtin/pull.c
 #, c-format
@@ -12086,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
@@ -12137,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
@@ -12174,9 +12189,9 @@ msgstr "nilai tidak valid untuk '%s'"
 msgid "repository"
 msgstr "repositori"
 
-#: builtin/push.c builtin/send-pack.c
-msgid "push all refs"
-msgstr "dorong semua referensi"
+#: builtin/push.c
+msgid "push all branches"
+msgstr "dorong semua cabang"
 
 #: builtin/push.c builtin/send-pack.c
 msgid "mirror all refs"
@@ -12187,8 +12202,10 @@ msgid "delete refs"
 msgstr "hapus referensi"
 
 #: builtin/push.c
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "dorong tag (tidak dapat digunakan dengan --all atau --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr ""
+"dorong tag (tidak dapat digunakan bersamaan dengan --all, --branches, atau --"
+"mirror)"
 
 #: builtin/push.c builtin/send-pack.c
 msgid "force updates"
@@ -12518,6 +12535,11 @@ msgstr ""
 "\n"
 "Hasilnya git tidak dapat mendasarkan ulang."
 
+#: builtin/rebase.c
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Mode rebase-merges tidak dikenal: %s"
+
 #: builtin/rebase.c
 #, c-format
 msgid "could not switch to %s"
@@ -12530,12 +12552,22 @@ 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\"."
 
+#: builtin/rebase.c
+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 dengan argumen untai kosong usang dan akan berhenti bekerja "
+"pada versi Git berikutnya. Sebagai gantinya, gunakan --rebase-merges tanpa "
+"argumen, yang melakukan hal yang sama."
+
 #: builtin/rebase.c
 #, c-format
 msgid ""
@@ -12802,23 +12834,26 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "tombol `C' harap nilai numerik"
 
-#: builtin/rebase.c
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Mode tidak dikenal: %s"
-
 #: builtin/rebase.c
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy butuh --merge atau --interactive"
 
 #: builtin/rebase.c
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"opsi penerapan tidak kompatibel dengan rebase.autosquash. "
+"opsi penerapan tidak kompatibel dengan rebase.autoSquash. "
 "Pertimbangkanmenambahkan --no-autosquash"
 
+#: builtin/rebase.c
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"opsi penerapan tidak kompatibel dengan rebase.rebaseMerges. "
+"Pertimbangkanmenambahkan --no-rebase-merges"
+
 #: builtin/rebase.c
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
@@ -12874,10 +12909,6 @@ msgstr "'%s': butuh tepatnya satu dasar penggabungan"
 msgid "Does not point to a valid commit '%s'"
 msgstr "Tidak menunjuk pada komit yang valid '%s'"
 
-#: builtin/rebase.c
-msgid "Please commit or stash them."
-msgstr "Mohon komit atau stase."
-
 #: builtin/rebase.c
 msgid "HEAD is up to date."
 msgstr "HEAD terbaru."
@@ -13189,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"
@@ -13693,8 +13724,8 @@ msgid "approxidate"
 msgstr "tanggal aproksimasi"
 
 #: builtin/repack.c
-msgid "with -C, expire objects older than this"
-msgstr "dengan -C, jangan kadaluarsakan objek lebih lama dari ini"
+msgid "with --cruft, expire objects older than this"
+msgstr "dengan --cruft, kadaluarsakan objek yang lebih tua dari ini"
 
 #: builtin/repack.c
 msgid "remove redundant packs, and run git-prune-packed"
@@ -14538,6 +14569,10 @@ msgstr ""
 msgid "remote name"
 msgstr "nama remote"
 
+#: builtin/send-pack.c
+msgid "push all refs"
+msgstr "dorong semua referensi"
+
 #: builtin/send-pack.c
 msgid "use stateless RPC protocol"
 msgstr "gunakan protokol RPC nirkeadaan"
@@ -14798,9 +14833,11 @@ msgstr ""
 
 #: builtin/sparse-checkout.c
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<opsi>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<opsi>]"
 
 #: builtin/sparse-checkout.c
 msgid "this worktree is not sparse"
@@ -14948,8 +14985,29 @@ msgstr ""
 "harus berada di dalam checkout tipis untuk menerapkan ulang pola kejarangan"
 
 #: builtin/sparse-checkout.c
-msgid "error while refreshing working directory"
-msgstr "kesalahan saat menyegarkan direktori kerja"
+msgid "error while refreshing working directory"
+msgstr "kesalahan saat menyegarkan direktori kerja"
+
+#: builtin/sparse-checkout.c
+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 <file>]"
+
+#: builtin/sparse-checkout.c
+msgid "terminate input and output files by a NUL character"
+msgstr "akhiri berkas masukan dan keluaran oleh satu karakter NUL"
+
+#: builtin/sparse-checkout.c
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
+"ketika digunakan dengan --rules-file tafsirkan pola sebagai pola mode kerucut"
+
+#: builtin/sparse-checkout.c
+msgid "use patterns in <file> instead of the current ones."
+msgstr "gunakan pola di dalam <berkas> daripada yang saat ini."
 
 #: builtin/stash.c
 msgid "git stash list [<log-options>]"
@@ -15599,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"
@@ -16531,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]]"
@@ -16564,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"
@@ -16647,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 ""
@@ -16665,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"
@@ -16690,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"
@@ -16975,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"
@@ -17278,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"
@@ -17821,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"
@@ -17928,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"
@@ -17963,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"
@@ -18020,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!"
@@ -18547,8 +18711,8 @@ msgid "bad zlib compression level %d"
 msgstr "level kompresi zlib jelek %d"
 
 #: config.c
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar harusnya hanya satu karakter"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar seharusnya hanya satu karakter ASCII"
 
 #: config.c
 #, c-format
@@ -18686,6 +18850,13 @@ msgstr "tidak dapat menyetel '%s' ke '%s'"
 msgid "invalid section name: %s"
 msgstr "nama bagian tidak valid: %s"
 
+#: config.c
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr ""
+"menolak bekerja dengan baris yang terlalu panjang di '%s' pada baris "
+"%<PRIuMAX>"
+
 #: config.c
 #, c-format
 msgid "missing value for '%s'"
@@ -19186,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>"
@@ -19253,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"
@@ -19272,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"
@@ -19517,6 +19701,10 @@ msgstr "tambah depan prefiks tambahan pada setiap baris keluaran"
 msgid "do not show any source or destination prefix"
 msgstr "jangan perlihatkan prefiks sumber atau tujuan apapun"
 
+#: diff.c
+msgid "use default prefixes a/ and b/"
+msgstr "gunakan awalan asali a/ dan b/"
+
 #: diff.c
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
@@ -19901,6 +20089,16 @@ msgstr "tidak dapat memigrasikan direktori git dari '%s' ke '%s'"
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "petunjuk: Menunggu penyunting Anda untuk menutup berkas...%c"
 
+#: editor.c sequencer.c wrapper.c
+#, c-format
+msgid "could not write to '%s'"
+msgstr "tidak dapat menulis ke '%s'"
+
+#: editor.c
+#, c-format
+msgid "could not edit '%s'"
+msgstr "tidak dapat menyunting '%s'"
+
 #: entry.c
 msgid "Filtering content"
 msgstr "Menyaring isi"
@@ -20271,6 +20469,11 @@ msgstr "-c mengharapkan sebuah untai konfigurasi\n"
 msgid "no config key given for --config-env\n"
 msgstr "tidak ada kunci konfigurasi yang diberikan untuk --config-env\n"
 
+#: git.c
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "tidak ada atribut yang diberikan untuk --attr-source\n"
+
 #: git.c
 #, c-format
 msgid "unknown option: %s\n"
@@ -21322,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"
@@ -22304,6 +22507,11 @@ msgstr "tidak dapat menemukan %s di dalam pak '%s' pada offset %<PRIuMAX>"
 msgid "unable to get disk usage of '%s'"
 msgstr "tidak dapat mendapatkan penggunaan disk dari '%s'"
 
+#: pack-bitmap.c
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "checksum berkas bitmap '%s' tidak valid"
+
 #: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s is too small"
@@ -22354,6 +22562,15 @@ msgstr "berkas indeks balik %s punya versi tidak didukung %<PRIu32>"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "berkas indeks balik %s punya id hash tidak didukung %<PRIu32>"
 
+#: pack-revindex.c
+msgid "invalid checksum"
+msgstr "checksum tidak valid"
+
+#: pack-revindex.c
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "posisi indeks balik tidak valid pada %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
 #: pack-write.c
 msgid "cannot both write and verify reverse index"
 msgstr "tidak dapat kedua-duanya menulis dan memverifikasi indeks balik"
@@ -22787,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)"
@@ -22977,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 --"
@@ -23198,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)"
@@ -23228,6 +23484,11 @@ msgstr "argumen %%(%s) tidak dikenal: %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "lebar positif diharapkan dengan atom %%(align)"
 
+#: ref-filter.c
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "format yang diharapkan: %%(ahead-behind:<mirip komit>)"
+
 #: ref-filter.c
 #, c-format
 msgid "malformed field name: %.*s"
@@ -23285,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)"
@@ -23362,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"
@@ -23902,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
@@ -23993,11 +24265,6 @@ msgstr "gagal memperbarui keadaan konflik di '%s'"
 msgid "no remembered resolution for '%s'"
 msgstr "tidak ada resolusi yang diingat untuk '%s'"
 
-#: rerere.c
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "tidak dapat batal taut '%s'"
-
 #: rerere.c
 #, c-format
 msgid "Updated preimage for '%s'"
@@ -24050,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"
@@ -24419,11 +24691,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "tidak dapat mengunci '%s'"
 
-#: sequencer.c strbuf.c wrapper.c
-#, c-format
-msgid "could not write to '%s'"
-msgstr "tidak dapat menulis ke '%s'"
-
 #: sequencer.c
 #, c-format
 msgid "could not write eol to '%s'"
@@ -24866,10 +25133,6 @@ msgstr "coba \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgid "could not create sequencer directory '%s'"
 msgstr "tidak dapat membuat direktori pembaris '%s'"
 
-#: sequencer.c
-msgid "could not lock HEAD"
-msgstr "tidak dapat mengunci HEAD"
-
 #: sequencer.c
 msgid "no cherry-pick or revert in progress"
 msgstr "tidak ada pemetikan ceri atau pembalikkan yang sedang berjalan"
@@ -24986,21 +25249,21 @@ msgstr ""
 "\n"
 
 #: sequencer.c
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "dan buat perubahan ke indeks dan/atau pohon kerja\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "dan buat perubahan ke indeks dan/atau pohon kerja.\n"
 
 #: sequencer.c
 #, 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 ""
 "eksekusi berhasil: %s\n"
-"tapi meninggalkan perubahan ke indeks dan/atau pohon kerja\n"
+"tapi meninggalkan perubahan ke indeks dan/atau pohon kerja.\n"
 "Komit atau stase perubahan Anda, lalu jalankan\n"
 "\n"
 "  git rebase --continue\n"
@@ -25467,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)"
@@ -25528,11 +25880,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u bita/detik"
 msgstr[1] "%u bita/detik"
 
-#: strbuf.c
-#, c-format
-msgid "could not edit '%s'"
-msgstr "tidak dapat menyunting '%s'"
-
 #: submodule-config.c
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
@@ -27643,14 +27990,19 @@ msgstr "(%s) Tidak dapat menjalankan '%s'"
 
 #: git-send-email.perl
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Menambahkan %s: %s dari: '%s'\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Baris masukan salah format: '%s'"
 
 #: git-send-email.perl
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) gagal menutup pipa ke '%s'"
 
+#: git-send-email.perl
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) Menambahkan %s: %s dari: '%s'\n"
+
 #: git-send-email.perl
 msgid "cannot send message as 7bit"
 msgstr "tidak dapat mengirim pesan sebagai 7bit"
@@ -27694,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 0ba8585b766d55944805a57753b00a077c6d566f..a14d0d6f38a3daefadd1bda92fddaa751ed807b7 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,12 +5,12 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.40.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-03-02 09:34+0100\n"
-"PO-Revision-Date: 2023-03-02 09:35+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"
@@ -665,6 +659,23 @@ msgstr "Checka in dina ändringar innan du utför sammanslagningen."
 msgid "Exiting because of unfinished merge."
 msgstr "Avslutar på grund av ofullbordad sammanslagning."
 
+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 ""
+"Divergerande grenar kan inte snabbspolas, du måste antingen använda:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"eller:\n"
+"\n"
+"\tgit rebase\n"
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "Kan inte snabbspola, avbryter."
 
@@ -773,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"
@@ -1109,6 +1126,10 @@ msgstr "trunkerar .rej-filnamnet till %.*s.rej"
 msgid "cannot open %s"
 msgstr "kan inte öppna %s"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "kan inte ta bort länken \"%s\""
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Stycke %d tillämpades rent."
@@ -1295,6 +1316,10 @@ msgstr "git archive --remote <arkiv> [--exec <kmd>] --list"
 msgid "cannot read '%s'"
 msgstr "kunde inte läsa \"%s\""
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "sökvägsangivelsen \"%s\" motsvarar filer utanför aktuell katalog"
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer"
@@ -1311,9 +1336,6 @@ msgstr "objektnamnet är inte giltigt: %s"
 msgid "not a tree object: %s"
 msgstr "inte ett trädobjekt: %s"
 
-msgid "current working directory is untracked"
-msgstr "aktuell arbetskatalog är inte spårad"
-
 #, c-format
 msgid "File not found: %s"
 msgstr "Hittar inte filen: %s"
@@ -1440,6 +1462,9 @@ msgstr "ignorerar allt för stor gitattributes-fil \"%s\""
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "ignorerar allt för stor gitattributes-objekt \"%s\""
 
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "felaktig --attr-source eller GIT_ATTR_SOURCE"
+
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Felaktigt citerat innehåll i filen \"%s\": %s"
@@ -1546,9 +1571,6 @@ msgstr[1] "Bisect: %d revisioner kvar att testa efter denna %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents och --reverse fungerar inte så bra tillsammans."
 
-msgid "cannot use --contents with final commit object name"
-msgstr "kan inte använda --contents med namn på slutgiltigt incheckningsobjekt"
-
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse och --first-parent tillsammans kräver att du anger senaste "
@@ -1667,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"
@@ -1731,10 +1754,6 @@ msgstr "undermodulen \"%s\": kan inte skapa grenen \"%s\""
 msgid "'%s' is already checked out at '%s'"
 msgstr "\"%s\" är redan utcheckad på \"%s\""
 
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "HEAD i arbetskatalogen %s har inte uppdaterats"
-
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<flaggor>] [--] <sökväg>..."
 
@@ -1742,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:"
 
@@ -2177,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"
 
@@ -2764,6 +2769,14 @@ msgstr "Kan inte ta bort grenen \"%s\" som är utcheckad på \"%s\""
 msgid "remote-tracking branch '%s' not found."
 msgstr "fjärrspårande grenen \"%s\" hittades inte."
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"grenen \"%s\" hittades inte.\n"
+"Glömde du --remote?"
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "grenen \"%s\" hittades inte."
@@ -2794,6 +2807,10 @@ msgstr "Grenen %s ombaseras på %s"
 msgid "Branch %s is being bisected at %s"
 msgstr "Grenen %s är i en \"bisect\" på %s"
 
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "HEAD i arbetskatalogen %s har inte uppdaterats"
+
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Felaktigt namn på gren: \"%s\""
@@ -2894,6 +2911,9 @@ msgstr "flytta/ta bort en gren och dess reflogg"
 msgid "move/rename a branch, even if target exists"
 msgstr "flytta/ta bort en gren, även om målet finns"
 
+msgid "do not output a newline after empty formatted refs"
+msgstr "skriv inte ut ett nyradstecken efter tomma formaterade referenser"
+
 msgid "copy a branch and its reflog"
 msgstr "kopiera en gren och dess reflogg"
 
@@ -3115,12 +3135,10 @@ msgid "Created new report at '%s'.\n"
 msgstr "Skapade ny rapport på \"%s\"\n"
 
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <fil> <git-rev-list-flaggor>"
 
 msgid "git bundle verify [-q | --quiet] <file>"
@@ -3141,11 +3159,11 @@ msgstr "visa inte förloppsindikator"
 msgid "show progress meter"
 msgstr "visa förloppsindikator"
 
-msgid "show progress meter during object writing phase"
-msgstr "visa förloppsindikator under objektskrivningsfasen"
+msgid "historical; same as --progress"
+msgstr "historisk; samma som --progress"
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "som --all-progress när förloppsindikatorn visas"
+msgid "historical; does nothing"
+msgstr "historisk flagga; gör ingenting"
 
 msgid "specify bundle format version"
 msgstr "ange formatversion för bunten."
@@ -3171,7 +3189,7 @@ msgid "cannot read object %s '%s'"
 msgstr "kan inte läsa objektet %s: \"%s\""
 
 msgid "flush is only for --buffer mode"
-msgstr "flush är endast till för --buffer-läge"
+msgstr "flush är endast till för \"--buffer\"-läge"
 
 msgid "empty command in input"
 msgstr "tomt kommando i indata"
@@ -3204,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"
@@ -3255,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"
 
@@ -4114,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"
 
@@ -4147,6 +4162,10 @@ msgstr "misslyckades ta status på \"%s\""
 msgid "%s exists and is not a directory"
 msgstr "%s finns och är ingen katalog"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "\"%s\" är en symbolisk länk, vägrar klona med --local"
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "misslyckades starta iterator över \"%s\""
@@ -4552,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"
 
@@ -4611,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"
@@ -5649,115 +5671,13 @@ msgstr "git fetch --all [<flaggor>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel kan inte vara negativt"
 
-msgid "fetch from all remotes"
-msgstr "hämta från alla fjärrar"
-
-msgid "set upstream for git pull/fetch"
-msgstr "ställ in uppström för git pull/fetch"
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "lägg till i .git/FETCH_HEAD istället för att skriva över"
-
-msgid "use atomic transaction to update references"
-msgstr "använd atomiska transaktioner för att uppdatera referenser"
-
-msgid "path to upload pack on remote end"
-msgstr "sökväg till upload pack på fjärren"
-
-msgid "force overwrite of local reference"
-msgstr "tvinga överskrivning av lokal referens"
-
-msgid "fetch from multiple remotes"
-msgstr "hämta från flera fjärrar"
-
-msgid "fetch all tags and associated objects"
-msgstr "hämta alla taggar och associerade objekt"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "hämta inte alla taggar (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "antal undermoduler som hämtas parallellt"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"modifiera referensspecifikationen så att alla referenser hamnar i refs/"
-"prefetch/"
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr "rensa fjärrspårande grenar ej längre på fjärren"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
-"rensa lokala taggar inte längre på fjärren och skriv över ändrade taggar"
-
-msgid "on-demand"
-msgstr "on-demand"
-
-msgid "control recursive fetching of submodules"
-msgstr "styr rekursiv hämtning av undermoduler"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "skriv hämtade referenser till FETCH_HEAD-filen"
-
-msgid "keep downloaded pack"
-msgstr "behåll hämtade paket"
-
-msgid "allow updating of HEAD ref"
-msgstr "tillåt uppdatering av HEAD-referens"
-
-msgid "deepen history of shallow clone"
-msgstr "fördjupa historik för grund klon"
-
-msgid "deepen history of shallow repository based on time"
-msgstr "fördjupa historik för grund klon baserad på tid"
-
-msgid "convert to a complete repository"
-msgstr "konvertera till komplett arkiv"
-
-msgid "re-fetch without negotiating common commits"
-msgstr "hämta om utan att förhandla om gemensamma incheckningar"
-
-msgid "prepend this to submodule path output"
-msgstr "lägg till i början av undermodulens sökvägsutdata"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"standard för rekursiv hämtning av undermoduler (lägre prioritet än "
-"konfigurationsfiler)"
-
-msgid "accept refs that update .git/shallow"
-msgstr "tar emot referenser som uppdaterar .git/shallow"
-
-msgid "refmap"
-msgstr "referenskarta"
-
-msgid "specify fetch refmap"
-msgstr "ange referenskarta för \"fetch\""
-
-msgid "report that we have only objects reachable from this object"
-msgstr "rapportera att vi bara har objekt nåbara från detta objektet"
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr "hämta inte paketfil; skriv istället förfäder till förhandlingstips"
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr "kör \"maintenance --auto\" efter hämtning"
-
-msgid "check for forced-updates on all updated branches"
-msgstr "se efter tvingade uppdateringar i alla uppdaterade grenar"
-
-msgid "write the commit-graph after fetching"
-msgstr "skriv incheckingsgrafen efter hämtning"
-
-msgid "accept refspecs from stdin"
-msgstr "ta emot referenser från standard in"
-
 msgid "couldn't find remote ref HEAD"
 msgstr "kunde inte hitta fjärr-referensen HEAD"
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "Från %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "objektet %s hittades inte"
@@ -5829,10 +5749,6 @@ msgstr "%s sände inte alla nödvändiga objekt\n"
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr "avvisade %s då grunda rötter inte tillåts uppdateras"
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "Från %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -5924,6 +5840,112 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "du måste ange namnet på en tagg"
 
+msgid "fetch from all remotes"
+msgstr "hämta från alla fjärrar"
+
+msgid "set upstream for git pull/fetch"
+msgstr "ställ in uppström för git pull/fetch"
+
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "lägg till i .git/FETCH_HEAD istället för att skriva över"
+
+msgid "use atomic transaction to update references"
+msgstr "använd atomiska transaktioner för att uppdatera referenser"
+
+msgid "path to upload pack on remote end"
+msgstr "sökväg till upload pack på fjärren"
+
+msgid "force overwrite of local reference"
+msgstr "tvinga överskrivning av lokal referens"
+
+msgid "fetch from multiple remotes"
+msgstr "hämta från flera fjärrar"
+
+msgid "fetch all tags and associated objects"
+msgstr "hämta alla taggar och associerade objekt"
+
+msgid "do not fetch all tags (--no-tags)"
+msgstr "hämta inte alla taggar (--no-tags)"
+
+msgid "number of submodules fetched in parallel"
+msgstr "antal undermoduler som hämtas parallellt"
+
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"modifiera referensspecifikationen så att alla referenser hamnar i refs/"
+"prefetch/"
+
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "rensa fjärrspårande grenar ej längre på fjärren"
+
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr ""
+"rensa lokala taggar inte längre på fjärren och skriv över ändrade taggar"
+
+msgid "on-demand"
+msgstr "on-demand"
+
+msgid "control recursive fetching of submodules"
+msgstr "styr rekursiv hämtning av undermoduler"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "skriv hämtade referenser till FETCH_HEAD-filen"
+
+msgid "keep downloaded pack"
+msgstr "behåll hämtade paket"
+
+msgid "allow updating of HEAD ref"
+msgstr "tillåt uppdatering av HEAD-referens"
+
+msgid "deepen history of shallow clone"
+msgstr "fördjupa historik för grund klon"
+
+msgid "deepen history of shallow repository based on time"
+msgstr "fördjupa historik för grund klon baserad på tid"
+
+msgid "convert to a complete repository"
+msgstr "konvertera till komplett arkiv"
+
+msgid "re-fetch without negotiating common commits"
+msgstr "hämta om utan att förhandla om gemensamma incheckningar"
+
+msgid "prepend this to submodule path output"
+msgstr "lägg till i början av undermodulens sökvägsutdata"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"standard för rekursiv hämtning av undermoduler (lägre prioritet än "
+"konfigurationsfiler)"
+
+msgid "accept refs that update .git/shallow"
+msgstr "tar emot referenser som uppdaterar .git/shallow"
+
+msgid "refmap"
+msgstr "referenskarta"
+
+msgid "specify fetch refmap"
+msgstr "ange referenskarta för \"fetch\""
+
+msgid "report that we have only objects reachable from this object"
+msgstr "rapportera att vi bara har objekt nåbara från detta objektet"
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr "hämta inte paketfil; skriv istället förfäder till förhandlingstips"
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr "kör \"maintenance --auto\" efter hämtning"
+
+msgid "check for forced-updates on all updated branches"
+msgstr "se efter tvingade uppdateringar i alla uppdaterade grenar"
+
+msgid "write the commit-graph after fetching"
+msgstr "skriv incheckingsgrafen efter hämtning"
+
+msgid "accept refspecs from stdin"
+msgstr "ta emot referenser från standard in"
+
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only behöver en eller flera --negotiation-tip=*"
 
@@ -6039,6 +6061,12 @@ msgstr "visa endast referenser som innehåller incheckningen"
 msgid "print only refs which don't contain the commit"
 msgstr "visa endast referenser som inte innehåller incheckningen"
 
+msgid "read reference patterns from stdin"
+msgstr "läs referensmönster från standard in"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "okända argument angavs tillsammans med --stdin"
+
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<konfig> [--] <argument>"
 
@@ -6051,6 +6079,10 @@ msgstr "konfigurationsnyckel som innehåller en lista över arkivsökvägar"
 msgid "missing --config=<config>"
 msgstr "saknar --config=<konfig>"
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "fick felaktig konfiguration --config=%s"
+
 msgid "unknown"
 msgstr "okänd"
 
@@ -6201,19 +6233,28 @@ msgstr "%s: frånkopplat HEAD pekar på ingenting"
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "obs: %s pekar på en ofödd gren (%s)"
 
-msgid "Checking cache tree"
-msgstr "Kontrollerar cacheträd"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Kontrollerar cacheträd för %s"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s: ogiltig sha1-pekare i cacheträd"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: ogiltig sha1-pekare i cacheträd för %s"
 
 msgid "non-tree in cache-tree"
 msgstr "icke-träd i cacheträd"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s: ogiltig sha1-pekare i resolve-undo"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: ogiltig sha1-pekare i resolve-undo för %s"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "kunde inte läsa rev-index för paketfil \"%s\""
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "ogiltigt rev-index för paketet \"%s\""
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -7186,80 +7227,9 @@ msgstr "--stdin kräver ett git-arkiv"
 msgid "--verify with no packfile name given"
 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 "fsck error in pack objects"
+msgstr "fsck-fel i packat objekt"
+
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7686,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 \"(\""
@@ -7828,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 \"(\""
@@ -8558,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>]"
@@ -8705,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 "
@@ -9055,6 +9038,12 @@ msgstr "indexversionen %s stöds ej"
 msgid "bad index version '%s'"
 msgstr "felaktig indexversion \"%s\""
 
+msgid "show progress meter during object writing phase"
+msgstr "visa förloppsindikator under objektskrivningsfasen"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "som --all-progress när förloppsindikatorn visas"
+
 msgid "<version>[,<offset>]"
 msgstr "<version>[,<offset>]"
 
@@ -9243,8 +9232,15 @@ msgstr ""
 "oss att du fortfarande använder det på e-post till\n"
 "<git@vger.kernel.org>. Tack.\n"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+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] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <mönster>] [--exclude "
+"<mönster>]"
 
 msgid "pack everything"
 msgstr "packa allt"
@@ -9252,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]"
 
@@ -9309,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."
@@ -9413,8 +9421,8 @@ msgstr "Uppdaterar en ofödd gren med ändringar som lagts till i indexet."
 msgid "pull with rebase"
 msgstr "pull med ombasering"
 
-msgid "please commit or stash them."
-msgstr "checka in eller använd \"stash\" på dem."
+msgid "Please commit or stash them."
+msgstr "Checka in eller använd \"stash\" på dem."
 
 #, c-format
 msgid ""
@@ -9569,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."
@@ -9616,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"
@@ -9648,8 +9657,8 @@ msgstr "ogiltigt värde för \"%s\""
 msgid "repository"
 msgstr "arkiv"
 
-msgid "push all refs"
-msgstr "sänd alla referenser"
+msgid "push all branches"
+msgstr "sänd alla grenar"
 
 msgid "mirror all refs"
 msgstr "spegla alla referenser"
@@ -9657,8 +9666,9 @@ msgstr "spegla alla referenser"
 msgid "delete refs"
 msgstr "ta bort referenser"
 
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "sänd taggar (kan inte användas med --all eller --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr ""
+"sänd taggar (kan inte användas med --all eller --branches eller --mirror)"
 
 msgid "force updates"
 msgstr "tvinga uppdateringar"
@@ -9920,6 +9930,10 @@ msgstr ""
 "\n"
 "Därför kan inte git ombasera dessa."
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Okänd rebase-merges-läge: %s"
+
 #, c-format
 msgid "could not switch to %s"
 msgstr "kunde inte växla till %s"
@@ -9935,6 +9949,15 @@ msgid ""
 msgstr ""
 "okänd tom-typ \"%s\"; giltiga värden är \"drop\", \"keep\" och \"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 med en tom sträng som argument avråds från och kommer sluta "
+"fungera i en framtida version av Git. Använd istället --rebase-merges utan "
+"argument, vilket har samma effekt."
+
 #, c-format
 msgid ""
 "%s\n"
@@ -10149,20 +10172,23 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "flaggan \"C\" förväntar ett numeriskt värde"
 
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Okänt läge: %s"
-
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy kräver --merge eller --interactive"
 
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"argument för \"apply\" är inkompatibla med rebase.autosquash. Överväg att "
+"argument för \"apply\" är inkompatibla med rebase.autoSquash. Överväg att "
 "lägga till --no-autosquash"
 
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"argument för \"apply\" är inkompatibla med rebase.rebaseMerges. Överväg att "
+"lägga till --no-rebase-merges"
+
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
@@ -10207,9 +10233,6 @@ msgstr "\"%s\": behöver precis en sammanslagningsbas"
 msgid "Does not point to a valid commit '%s'"
 msgstr "Pekar inte på en giltig incheckning: \"%s\""
 
-msgid "Please commit or stash them."
-msgstr "Checka in eller använd \"stash\" på dem."
-
 msgid "HEAD is up to date."
 msgstr "HEAD är à jour."
 
@@ -10464,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"
@@ -10863,8 +10887,8 @@ msgstr "samma som -a, packa onåbara onödiga objekt separat"
 msgid "approxidate"
 msgstr "cirkadatum"
 
-msgid "with -C, expire objects older than this"
-msgstr "med -C, låt tid gå ut för objekt äldre än detta"
+msgid "with --cruft, expire objects older than this"
+msgstr "med --cruft, låt tid gå ut för objekt äldre än detta"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "ta bort överflödiga paket, och kör git-prune-packed"
@@ -11528,6 +11552,9 @@ msgstr ""
 msgid "remote name"
 msgstr "fjärrnamn"
 
+msgid "push all refs"
+msgstr "sänd alla referenser"
+
 msgid "use stateless RPC protocol"
 msgstr "använd tillståndslöst RPC-protokoll"
 
@@ -11728,9 +11755,11 @@ msgid "show refs from stdin that aren't in local repository"
 msgstr "visa referenser från standard in som inte finns i lokalt arkiv"
 
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) <flaggor>"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) <flaggor>"
 
 msgid "this worktree is not sparse"
 msgstr "arbetskatalogen är inte gren"
@@ -11853,6 +11882,22 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr "fel vid uppdatering av arbetskatalog"
 
+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 <fil>]"
+
+msgid "terminate input and output files by a NUL character"
+msgstr "avsluta in- och utdatafiler med NUL-tecken"
+
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr "om används med --rules-file tolka mönster som kon-lägemönster"
+
+msgid "use patterns in <file> instead of the current ones."
+msgstr "använd mönster i <fil> istället för de nuvarande."
+
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [<\"log\"-flaggor>]"
 
@@ -12369,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"
@@ -13105,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]]"
@@ -13131,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"
@@ -13201,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"
@@ -13215,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"
 
@@ -13234,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"
 
@@ -13462,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"
 
@@ -13687,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"
@@ -14094,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"
@@ -14177,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"
 
@@ -14208,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 ""
@@ -14259,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!"
@@ -14685,8 +14822,8 @@ msgstr "förkortningslängd utanför intervallet: %d"
 msgid "bad zlib compression level %d"
 msgstr "felaktigt zlib-komprimeringsgrad %d"
 
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar kan bara vara ett tecken"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar kan bara vara ett ASCII-tecken"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -14797,6 +14934,10 @@ msgstr "kunde inte ställa in \"%s\" till \"%s\""
 msgid "invalid section name: %s"
 msgstr "felaktigt namn på stycke: %s"
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr "vägrar arbeta med för långa rader i \"%s\" på rad %<PRIuMAX>"
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr "värde saknas för \"%s\""
@@ -15199,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>"
 
@@ -15256,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 ""
@@ -15274,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"
@@ -15466,6 +15617,9 @@ msgstr "lägg till ytterligare prefix på alla rader i utdata"
 msgid "do not show any source or destination prefix"
 msgstr "visa inte käll- eller målprefix"
 
+msgid "use default prefixes a/ and b/"
+msgstr "använd standardprefixen a/ och b/"
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr "visa sammnhang mellan diff-stycken upp till angivet antal rader"
 
@@ -15759,6 +15913,14 @@ msgstr "kunde inte migrera git-katalog från \"%s\" till \"%s\""
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "tips: Väntar på att textredigeringsprogrammet ska stänga filen...%c"
 
+#, c-format
+msgid "could not write to '%s'"
+msgstr "kunde inte skriva till \"%s\""
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr "kunde inte redigera \"%s\""
+
 msgid "Filtering content"
 msgstr "Filtrerar innehåll"
 
@@ -16056,6 +16218,10 @@ msgstr "-c förväntar en konfigurationssträng\n"
 msgid "no config key given for --config-env\n"
 msgstr "ingen konfigurationsnyckel angavs för --config-env\n"
 
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "ingen attributkälla angavs för --attr-source\n"
+
 #, c-format
 msgid "unknown option: %s\n"
 msgstr "okänd flagga: %s\n"
@@ -17715,6 +17881,10 @@ msgstr "kunde inte hitta \"%s\" i paketet \"%s\" på offset %<PRIuMAX>"
 msgid "unable to get disk usage of '%s'"
 msgstr "kan inte hämta diskanvändning för \"%s\""
 
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "bitkartefilen \"%s\" har ogiltig kontrollsumma"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "mtimes-filen %s är för liten"
@@ -17755,6 +17925,13 @@ msgstr "reverse-index-filen %s har versionen %<PRIu32> som inte stöds"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "reverse-index-filen %s har hash-ID %<PRIu32> som inte stöds"
 
+msgid "invalid checksum"
+msgstr "ogiltig kontrollsumma"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "ogiltig rev-indexposition vid %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
 msgid "cannot both write and verify reverse index"
 msgstr "kan inte både skriva och bekräfta reverse-index"
 
@@ -18098,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)"
@@ -18249,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"
@@ -18452,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)"
@@ -18476,6 +18684,10 @@ msgstr "okänt %%(%s)-argument: %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "positiv bredd förväntad med atomen %%(align)"
 
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "förväntat format: %%(ahead-behind:<incheckning-igt>)"
+
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "felformat fältnamn: %.*s"
@@ -18522,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)"
@@ -18583,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"
@@ -19022,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'"
@@ -19095,10 +19315,6 @@ msgstr "misslyckades uppdatera tillstånd för sammanslagningsproblem i \"%s\""
 msgid "no remembered resolution for '%s'"
 msgstr "inget sparat sammanslagningsresultat för \"%s\""
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "kan inte ta bort länken \"%s\""
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "Uppdaterade förhandsbild för \"%s\""
@@ -19138,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"
 
@@ -19431,10 +19651,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "kunde inte låsa \"%s\""
 
-#, c-format
-msgid "could not write to '%s'"
-msgstr "kunde inte skriva till \"%s\""
-
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "kunde inte skriva radslut till \"%s\""
@@ -19795,9 +20011,6 @@ msgstr "testa \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgid "could not create sequencer directory '%s'"
 msgstr "kunde inte skapa \"sequencer\"-katalogen \"%s\""
 
-msgid "could not lock HEAD"
-msgstr "kunde inte låsa HEAD"
-
 msgid "no cherry-pick or revert in progress"
 msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
 
@@ -19894,20 +20107,20 @@ msgstr ""
 "\tgit rebase --continue\n"
 "\n"
 
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "och gjorde ändringar till indexet och/eller arbetskatalogen\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "och gjorde ändringar till indexet och/eller arbetskatalogen.\n"
 
 #, 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 ""
 "körningen lyckades: %s\n"
-"men lämnade kvar ändringar i indexet och/eller arbetskatalogen\n"
+"men lämnade kvar ändringar i indexet och/eller arbetskatalogen.\n"
 "Checka in eller utför \"stash\" på ändringarna och kör sedan\n"
 "\n"
 "\tgit rebase --continue\n"
@@ -20290,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)"
@@ -20341,10 +20625,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u byte/s"
 msgstr[1] "%u bytes/s"
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr "kunde inte redigera \"%s\""
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "ignorerar misstänkt undermodulnamn: %s"
@@ -22058,13 +22338,17 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) Kunde inte köra \"%s\""
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Lägger till %s: %s från: \"%s\"\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Felformaterad utdata från \"%s\""
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) misslyckades stänga röret till \"%s\""
 
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) Lägger till %s: %s från: \"%s\"\n"
+
 msgid "cannot send message as 7bit"
 msgstr "kan inte sända brev som sjubitars"
 
index a24a7ae9cb42a8bf1e98e7a6ae3bc5304cef5c10..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-03-03 11:32+0300\n"
-"PO-Revision-Date: 2023-03-03 11:40+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"
@@ -741,6 +744,23 @@ msgstr "Birleştirme öncesinde değişikliklerinizi işleyin."
 msgid "Exiting because of unfinished merge."
 msgstr "Tamamlanmamış birleştirmeden dolayı çıkılıyor."
 
+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 ""
+"Iraksak dallar ileri sarılamaz; şunlardan birini yapmanız gerekiyor:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"veya\n"
+"\n"
+"\tgit rebase\n"
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "İleri sarma olanaklı değil, iptal ediliyor."
 
@@ -849,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"
@@ -1182,6 +1208,10 @@ msgstr ".rej dosya adı %.*s.rej olarak kısaltılıyor"
 msgid "cannot open %s"
 msgstr "%s açılamıyor"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "'%s' bağlantısı kesilemiyor"
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Parça #%d sorunsuzca uygulandı."
@@ -1365,9 +1395,13 @@ msgstr "git archive --remote <depo> [--exec <komut>] --list"
 msgid "cannot read '%s'"
 msgstr "'%s' okunamıyor"
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "yol belirteci '%s', geçerli dizinin dışındaki dosyalarla eşleşiyor"
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
-msgstr "yol belirteci '%s' hiçbir dosya ile eşleşmedi"
+msgstr "yol belirteci '%s', hiçbir dosya ile eşleşmedi"
 
 #, c-format
 msgid "no such ref: %.*s"
@@ -1381,9 +1415,6 @@ msgstr "geçerli bir nesne adı değil: %s"
 msgid "not a tree object: %s"
 msgstr "bir ağaç nesnesi değil: %s"
 
-msgid "current working directory is untracked"
-msgstr "geçerli çalışma dizini izlenmiyor"
-
 #, c-format
 msgid "File not found: %s"
 msgstr "Dosya bulunamadı: %s"
@@ -1510,6 +1541,9 @@ msgstr "pek büyük gitattributes dosyası '%s' dosyası yok sayılıyor"
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "pek büyük gitattributes ikili nesnesi '%s' yok sayılıyor"
 
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "hatalı --attr-source veya GIT_ATTR_SOURCE"
+
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "'%s' dosyasında hatalı tırnağa alınmış içerik: %s"
@@ -1615,9 +1649,6 @@ msgstr[1] "İkili arama: Şundan sonra sınanacak %d revizyon kaldı: %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents ve --reverse birlikte pek iyi gitmiyor."
 
-msgid "cannot use --contents with final commit object name"
-msgstr "--contents son işleme nesnesi adı ile kullanılamıyor"
-
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse ve --first-parent birlikte en son işlemenin belirtilmesini "
@@ -1738,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"
@@ -1800,10 +1833,6 @@ msgstr "'%s' altmodülü: '%s' dalı oluşturulamıyor"
 msgid "'%s' is already checked out at '%s'"
 msgstr "'%s' çıkışı '%s' konumunda halihazırda yapılmış"
 
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "%s çalışma ağacının HEAD'i güncellenmemiş"
-
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<seçenekler>] [--] <yol-blrtç>..."
 
@@ -1811,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:"
 
@@ -2252,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"
 
@@ -2837,6 +2851,14 @@ msgstr "'%s' dalı silinemiyor, şurada çıkış yapılmış: '%s'"
 msgid "remote-tracking branch '%s' not found."
 msgstr "Uzak izleme dalı '%s' bulunamadı."
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"'%s' dalı bulunamadı.\n"
+"--remote yazmayı mı unuttunuz?"
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "'%s' dalı bulunamadı."
@@ -2867,6 +2889,10 @@ msgstr "%s dalı %s konumunda yeniden temellendiriliyor"
 msgid "Branch %s is being bisected at %s"
 msgstr "%s dalı %s konumunda ikili aranıyor"
 
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "%s çalışma ağacının HEAD'i güncellenmemiş"
+
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Geçersiz dal adı: '%s'"
@@ -2967,6 +2993,9 @@ msgstr "bir dalı ve onun başvuru günlüğünü taşı/yeniden adlandır"
 msgid "move/rename a branch, even if target exists"
 msgstr "bir dalı taşı/yeniden adlandır, hedef var olsa bile"
 
+msgid "do not output a newline after empty formatted refs"
+msgstr "boş biçimli başvurulardan sonra bir yenisatır çıktılama"
+
 msgid "copy a branch and its reflog"
 msgstr "bir dalı ve onun başvuru günlüğünü kopyala"
 
@@ -3185,13 +3214,11 @@ msgid "Created new report at '%s'.\n"
 msgstr "Hata raporu '%s' dosyasına yazıldı.\n"
 
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
-"                  [--version=<sürüm>] <dosya> <git-rev-liste-argümanları>"
+"git bundle create [-q | --quiet | --progress]\n"
+"                  [--version=<sürüm>] <dosya> <git-rev-listesi-argümanları>"
 
 msgid "git bundle verify [-q | --quiet] <file>"
 msgstr "git bundle verify [-q | --quiet] <dosya>"
@@ -3211,11 +3238,11 @@ msgstr "ilerleme çubuğunu gösterme"
 msgid "show progress meter"
 msgstr "ilerleme çubuğunu göster"
 
-msgid "show progress meter during object writing phase"
-msgstr "ilerleme çubuğunu nesne yazımı aşaması sırasında göster"
+msgid "historical; same as --progress"
+msgstr "eski seçenek; --progress ile aynı"
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "ilerleme çubuğu gösterildiğinde --all-progress'e benzer"
+msgid "historical; does nothing"
+msgstr "eski seçenek; bir şey yapmaz"
 
 msgid "specify bundle format version"
 msgstr "demet biçim sürümünü belirt"
@@ -3274,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"
@@ -3324,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"
 
@@ -4185,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"
 
@@ -4220,6 +4244,10 @@ msgstr "'%s' dosyasının bilgileri alınamadı"
 msgid "%s exists and is not a directory"
 msgstr "%s var ve bir dizin değil"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "'%s' bir sembolik bağlantı; --local ile klonlama reddediliyor"
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "yineleyici '%s' üzerinden çalıştırılamadı"
@@ -4626,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ı"
 
@@ -4685,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"
@@ -5733,118 +5764,13 @@ msgstr "git fetch --all [<seçenekler>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel negatif olamaz"
 
-msgid "fetch from all remotes"
-msgstr "tüm uzak konumlardan getir"
-
-msgid "set upstream for git pull/fetch"
-msgstr "git pull/fetch için üstkaynak ayarla"
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr ".git/FETCH_HEAD'in üzerine yazmak yerine ona iliştir"
-
-msgid "use atomic transaction to update references"
-msgstr "başvuruları güncellemek için atomsal işlem kullan"
-
-msgid "path to upload pack on remote end"
-msgstr "uzak uçtaki yükleme paketine olan yol"
-
-msgid "force overwrite of local reference"
-msgstr "yerel başvurunun üzerine zorla yaz"
-
-msgid "fetch from multiple remotes"
-msgstr "birden çok uzak konumdan getir"
-
-msgid "fetch all tags and associated objects"
-msgstr "tüm etiketleri ve ilişkilendirilen nesneleri getir"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "tüm etiketleri getirme (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "paralelde getirilen altmodüllerin sayısı"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"başvuru belirtecini tüm başvuruları refs/prefetch/'e yerleştirecek biçimde "
-"değiştir"
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr "artık uzak konumda olmayan uzak izleme dallarını buda"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
-"artık uzak konumda olmayan yerel etiketleri buda ve değiştirilen etiketleri "
-"güncelle"
-
-msgid "on-demand"
-msgstr "istek üzerine"
-
-msgid "control recursive fetching of submodules"
-msgstr "altmodüllerin özyineli getirilmesini denetle"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "getirilen başvuruları FETCH_HEAD dosyasına yaz"
-
-msgid "keep downloaded pack"
-msgstr "indirilen paketi tut"
-
-msgid "allow updating of HEAD ref"
-msgstr "HEAD başvurusunun güncellenmesine izin ver"
-
-msgid "deepen history of shallow clone"
-msgstr "sığ klonun geçmişini derinleştir"
-
-msgid "deepen history of shallow repository based on time"
-msgstr "zamana bağlı olarak sığ deponun geçmişini derinleştir"
-
-msgid "convert to a complete repository"
-msgstr "tam bir depoya dönüştür"
-
-msgid "re-fetch without negotiating common commits"
-msgstr "ortak işlemeleri pazarlık etmeden yeniden getir"
-
-msgid "prepend this to submodule path output"
-msgstr "bunu altmodül yol çıktısının başına ekle"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"altmodüllerin özyineli getirilmesi için öntanımlı (yapılandırma "
-"dosyalarından daha az önceliğe iye)"
-
-msgid "accept refs that update .git/shallow"
-msgstr ".git/shallow'u güncelleyen başvuruları kabul et"
-
-msgid "refmap"
-msgstr "ilgili başvuru"
-
-msgid "specify fetch refmap"
-msgstr "getirme ile ilgili başvuruları belirt"
-
-msgid "report that we have only objects reachable from this object"
-msgstr "yalnızca bu nesneden ulaşılabilir nesnelerimiz olduğunu bildir"
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-"bir paket dosyasını getirme; bunun yerine pazarlık ipuçlarının atalarını "
-"yazdır"
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr "getirme sonrasında 'maintenance --auto' çalıştır"
-
-msgid "check for forced-updates on all updated branches"
-msgstr "tüm güncellenmiş dalları zorlanmış güncellemeler için denetle"
-
-msgid "write the commit-graph after fetching"
-msgstr "getirdikten sonra işleme grafiğini yaz"
-
-msgid "accept refspecs from stdin"
-msgstr "başvuru belirteçlerini stdin'den oku"
-
 msgid "couldn't find remote ref HEAD"
 msgstr "uzak HEAD başvurusu bulunamadı"
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "Şu konumdan: %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "%s nesnesi bulunamadı"
@@ -5915,10 +5841,6 @@ msgstr "%s tüm gerekli nesneleri göndermedi\n"
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr "%s reddedildi; çünkü sığ köklerin güncellenmesine izin verilmiyor"
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "Şu konumdan: %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -6010,6 +5932,115 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "bir etiket adı belirtmeniz gerekiyor"
 
+msgid "fetch from all remotes"
+msgstr "tüm uzak konumlardan getir"
+
+msgid "set upstream for git pull/fetch"
+msgstr "git pull/fetch için üstkaynak ayarla"
+
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr ".git/FETCH_HEAD'in üzerine yazmak yerine ona iliştir"
+
+msgid "use atomic transaction to update references"
+msgstr "başvuruları güncellemek için atomsal işlem kullan"
+
+msgid "path to upload pack on remote end"
+msgstr "uzak uçtaki yükleme paketine olan yol"
+
+msgid "force overwrite of local reference"
+msgstr "yerel başvurunun üzerine zorla yaz"
+
+msgid "fetch from multiple remotes"
+msgstr "birden çok uzak konumdan getir"
+
+msgid "fetch all tags and associated objects"
+msgstr "tüm etiketleri ve ilişkilendirilen nesneleri getir"
+
+msgid "do not fetch all tags (--no-tags)"
+msgstr "tüm etiketleri getirme (--no-tags)"
+
+msgid "number of submodules fetched in parallel"
+msgstr "paralelde getirilen altmodüllerin sayısı"
+
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"başvuru belirtecini tüm başvuruları refs/prefetch/'e yerleştirecek biçimde "
+"değiştir"
+
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "artık uzak konumda olmayan uzak izleme dallarını buda"
+
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr ""
+"artık uzak konumda olmayan yerel etiketleri buda ve değiştirilen etiketleri "
+"güncelle"
+
+msgid "on-demand"
+msgstr "istek üzerine"
+
+msgid "control recursive fetching of submodules"
+msgstr "altmodüllerin özyineli getirilmesini denetle"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "getirilen başvuruları FETCH_HEAD dosyasına yaz"
+
+msgid "keep downloaded pack"
+msgstr "indirilen paketi tut"
+
+msgid "allow updating of HEAD ref"
+msgstr "HEAD başvurusunun güncellenmesine izin ver"
+
+msgid "deepen history of shallow clone"
+msgstr "sığ klonun geçmişini derinleştir"
+
+msgid "deepen history of shallow repository based on time"
+msgstr "zamana bağlı olarak sığ deponun geçmişini derinleştir"
+
+msgid "convert to a complete repository"
+msgstr "tam bir depoya dönüştür"
+
+msgid "re-fetch without negotiating common commits"
+msgstr "ortak işlemeleri pazarlık etmeden yeniden getir"
+
+msgid "prepend this to submodule path output"
+msgstr "bunu altmodül yol çıktısının başına ekle"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"altmodüllerin özyineli getirilmesi için öntanımlı (yapılandırma "
+"dosyalarından daha az önceliğe iye)"
+
+msgid "accept refs that update .git/shallow"
+msgstr ".git/shallow'u güncelleyen başvuruları kabul et"
+
+msgid "refmap"
+msgstr "ilgili başvuru"
+
+msgid "specify fetch refmap"
+msgstr "getirme ile ilgili başvuruları belirt"
+
+msgid "report that we have only objects reachable from this object"
+msgstr "yalnızca bu nesneden ulaşılabilir nesnelerimiz olduğunu bildir"
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+"bir paket dosyasını getirme; bunun yerine pazarlık ipuçlarının atalarını "
+"yazdır"
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr "getirme sonrasında 'maintenance --auto' çalıştır"
+
+msgid "check for forced-updates on all updated branches"
+msgstr "tüm güncellenmiş dalları zorlanmış güncellemeler için denetle"
+
+msgid "write the commit-graph after fetching"
+msgstr "getirdikten sonra işleme grafiğini yaz"
+
+msgid "accept refspecs from stdin"
+msgstr "başvuru belirteçlerini stdin'den oku"
+
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only'e bir veya daha çok --negotiation-tip=* gerekiyor"
 
@@ -6125,6 +6156,12 @@ msgstr "yalnızca işlemeyi içeren başvuruları yazdır"
 msgid "print only refs which don't contain the commit"
 msgstr "yalnızca işlemeyi içermeyen başvuruları yazdır"
 
+msgid "read reference patterns from stdin"
+msgstr "başvuru dizgilerini stdin'den oku"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "--stdin ile bilinmeyen argümanlar verilmiş"
+
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<yapılandırma> [--] <argümanlar>"
 
@@ -6137,6 +6174,10 @@ msgstr "bir depo yolları listesi tutan yapılandırma anahtarı"
 msgid "missing --config=<config>"
 msgstr "--config=<yapılandırma> eksik"
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "hatayı yapılandırma alındı, --config=%s"
+
 msgid "unknown"
 msgstr "bilinmeyen"
 
@@ -6283,19 +6324,28 @@ msgstr "%s: ayrık HEAD bir şeye işaret etmiyor"
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "Uyarı: %s henüz doğmamış bir dala işaret ediyor (%s)"
 
-msgid "Checking cache tree"
-msgstr "Önbellek ağacı denetleniyor"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "%s ögesinin önbellek ağacı denetleniyor"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s: cache-tree içinde geçersiz sha1 işaretçisi"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: %s ögesinin cache-tree'si içinde geçersiz sha1 işaretçisi"
 
 msgid "non-tree in cache-tree"
 msgstr "cache-tree içinde ağaç olmayan öge"
 
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s: resolve-undo içinde geçersiz sha1 işaretçisi"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: %s ögesinin resolve-undo'su içinde geçersiz sha1 işaretçisi"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "'%s' paketi için rev-index yüklenemiyor"
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "'%s' paketi için geçersiz rev-index"
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -7271,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"
@@ -7771,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"
@@ -7913,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"
@@ -8641,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>]"
@@ -8786,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 "
@@ -9139,6 +9131,12 @@ msgstr "desteklenmeyen indeks sürümü %s"
 msgid "bad index version '%s'"
 msgstr "hatalı indeks sürümü '%s'"
 
+msgid "show progress meter during object writing phase"
+msgstr "ilerleme çubuğunu nesne yazımı aşaması sırasında göster"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "ilerleme çubuğu gösterildiğinde --all-progress'e benzer"
+
 msgid "<version>[,<offset>]"
 msgstr "<sürüm>[,<ofset>]"
 
@@ -9329,8 +9327,15 @@ msgstr ""
 "<git@vger.kernel.org> adresine bir e-posta atarak\n"
 "bize haber verin. Sağ olun.\n"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+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] [--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"
@@ -9338,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]"
 
@@ -9396,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."
@@ -9499,7 +9516,7 @@ msgstr "İndekse eklenen değişikliklerle henüz doğmamış bir dal güncellen
 msgid "pull with rebase"
 msgstr "yeniden temellendirme ile çekim"
 
-msgid "please commit or stash them."
+msgid "Please commit or stash them."
 msgstr "Lütfen onları işleyin veya zulalayın."
 
 #, c-format
@@ -9654,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."
 
@@ -9703,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'"
@@ -9735,8 +9753,8 @@ msgstr "'%s' için geçersiz değer"
 msgid "repository"
 msgstr "depo"
 
-msgid "push all refs"
-msgstr "tüm başvuruları it"
+msgid "push all branches"
+msgstr "tüm dalları it"
 
 msgid "mirror all refs"
 msgstr "tüm başvuruları yansıla"
@@ -9744,11 +9762,11 @@ msgstr "tüm başvuruları yansıla"
 msgid "delete refs"
 msgstr "başvuruları sil"
 
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "etiketleri it (--all veya --mirror ile kullanılamaz)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr "etiketleri it (--all, --branches  veya --mirror ile kullanılamaz)"
 
 msgid "force updates"
-msgstr "zorla güncelle"
+msgstr "güncellemeleri zorla"
 
 msgid "<refname>:<expect>"
 msgstr "<bşvr-adı>:<bekle>"
@@ -10008,6 +10026,10 @@ msgstr ""
 "\n"
 "Bunun sonucu olarak git onları yeniden temellendiremiyor."
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Bilinmeyen rebase-merges kipi: %s"
+
 #, c-format
 msgid "could not switch to %s"
 msgstr "şuraya geçilemedi: %s"
@@ -10022,6 +10044,15 @@ msgid ""
 msgstr ""
 "Tanımlanamayan boş tür '%s'; geçerli türler: \"drop\", \"keep\" ve \"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 ""
+"bir boş dizi argümanıyla --rebase-merges yapmak artık kullanılmıyor ve "
+"Git'in ileriki bir sürümünde tümüyle kaldırılacak. Bunun yerine, aynı şeyi "
+"yapan argümansız bir --rebase-merges kullanın."
+
 #, c-format
 msgid ""
 "%s\n"
@@ -10243,18 +10274,21 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "'C' anahtarı sayısal bir değer bekliyor"
 
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Bilinmeyen kip: %s"
-
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy, --merge veya --interactive gerektiriyor"
 
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
-"uygulama seçenekleri, rebase.autosquash ile uyumlu değil. --no-autosquash "
+"seçenekleri uygula, rebase.autoSquash ile uyumlu değil. --no-autosquash "
+"eklemeyi düşünün"
+
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"seçenekleri uygula, rebase.rebaseMerges ile uyumlu değil. --no-rebase-merges "
 "eklemeyi düşünün"
 
 msgid ""
@@ -10301,9 +10335,6 @@ msgstr "'%s': tam olarak bir birleştirme temeli gerekiyor"
 msgid "Does not point to a valid commit '%s'"
 msgstr "'%s' geçerli bir işlemeye işaret etmiyor"
 
-msgid "Please commit or stash them."
-msgstr "Lütfen onları işleyin veya zulalayın."
-
 msgid "HEAD is up to date."
 msgstr "HEAD güncel."
 
@@ -10560,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)"
@@ -10965,8 +10997,8 @@ msgstr "-a ile aynı, ulaşılamayan süprüntü nesneleri ayrı paketle"
 msgid "approxidate"
 msgstr "yaklaşık tarih"
 
-msgid "with -C, expire objects older than this"
-msgstr "-C ile, bundan daha eski nesneleri yürürlükten kaldır"
+msgid "with --cruft, expire objects older than this"
+msgstr "--cruft ile, bundan daha eski nesneleri yürürlükten kaldır"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "gereksiz paketleri kaldır ve 'git-prune-packed' çalıştır"
@@ -11634,6 +11666,9 @@ msgstr ""
 msgid "remote name"
 msgstr "uzak konum adı"
 
+msgid "push all refs"
+msgstr "tüm başvuruları it"
+
 msgid "use stateless RPC protocol"
 msgstr "durumsuz RPC protokolünü kullan"
 
@@ -11834,9 +11869,11 @@ msgid "show refs from stdin that aren't in local repository"
 msgstr "stdin'den yerel bir depoda olmayan başvuruları göster"
 
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<sçnklr>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<seçenekler>]"
 
 msgid "this worktree is not sparse"
 msgstr "bu çalışma ağacı aralıklı değil"
@@ -11958,6 +11995,23 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr "çalışma dizini yenilenirken hata"
 
+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 <dosya>]"
+
+msgid "terminate input and output files by a NUL character"
+msgstr "girdi ve çıktı dosyalarını bir NUL karakteri ile sonlandır"
+
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
+"--rules-file ile kullanıldığında dizgileri koni kipi dizgileri olarak yorumla"
+
+msgid "use patterns in <file> instead of the current ones."
+msgstr "geçerli dizgiler yerine <dosya> içindekileri kullan."
+
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [<günlük-seçenekleri>]"
 
@@ -12471,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ı"
@@ -13208,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]]"
@@ -13234,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"
@@ -13300,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"
 
@@ -13313,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"
 
@@ -13332,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"
 
@@ -13559,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"
 
@@ -13783,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"
@@ -14190,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"
@@ -14274,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"
 
@@ -14303,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 ""
@@ -14351,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!"
@@ -14778,8 +14923,8 @@ msgstr "kısaltma uzunluğu erim dışında: %d"
 msgid "bad zlib compression level %d"
 msgstr "hatalı zlib sıkıştırma düzeyi %d"
 
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar yalnızca bir karakter olmalı"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar yalnızca bir ASCII karakter olmalı"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -14889,6 +15034,10 @@ msgstr "'%s', '%s' olarak ayarlanamadı"
 msgid "invalid section name: %s"
 msgstr "geçersiz bölüm adı: %s"
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr "'%s' içindeki haddinden uzun %<PRIuMAX>. satırla çalışma reddediliyor"
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr "'%s' için değer eksik"
@@ -15294,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>"
 
@@ -15350,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"
@@ -15367,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"
@@ -15559,6 +15718,9 @@ msgstr "çıktının her satırının başına ek bir önek ekle"
 msgid "do not show any source or destination prefix"
 msgstr "hiçbir kaynak ve hedef önekini gösterme"
 
+msgid "use default prefixes a/ and b/"
+msgstr "a/ ve b/ ögelerinin öntanımlı öneklerini kullan"
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr "diff parçaları arasındaki bağlamı belirtilen satır sayısı kadar göster"
 
@@ -15856,6 +16018,14 @@ msgstr "git dizini '%s' konumundan '%s' konumuna göç ettirilemedi"
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "İpucu: Düzenleyicinizin dosyayı kapatması bekleniyor...%c"
 
+#, c-format
+msgid "could not write to '%s'"
+msgstr "şuraya yazılamadı: '%s'"
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr "'%s' düzenlenemedi"
+
 msgid "Filtering content"
 msgstr "İçerik süzülüyor"
 
@@ -16150,6 +16320,10 @@ msgstr "-c bir yapılandırma dizisi bekliyor\n"
 msgid "no config key given for --config-env\n"
 msgstr "--config-env için bir yapılandırma anahtarı verilmedi\n"
 
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "--attr-source için öznitelik kaynağı verilmedi\n"
+
 #, c-format
 msgid "unknown option: %s\n"
 msgstr "bilinmeyen seçenek: %s\n"
@@ -17822,6 +17996,10 @@ msgstr "öge bulunamadı: '%s'; '%s' paketinde, %<PRIuMAX> ofsetinde"
 msgid "unable to get disk usage of '%s'"
 msgstr "'%s' ögesinin disk kullanımı alınamadı"
 
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "biteşlem dosyası '%s', geçersiz sağlama toplamına iye"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "mtimes dosyası %s pek küçük"
@@ -17862,6 +18040,13 @@ msgstr "%s reverse-index dosyasının sürümü %<PRIu32> desteklenmiyor"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "%s reverse-index dosyasının sağlama numarası %<PRIu32> desteklenmiyor"
 
+msgid "invalid checksum"
+msgstr "geçersiz sağlama toplamı"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "%<PRIu64> konumunda geçersiz rev-index konumu: %<PRIu32> != %<PRIu32>"
+
 msgid "cannot both write and verify reverse index"
 msgstr "ters indeks dosyası hem yazılıp hem doğrulanamıyor"
 
@@ -18202,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)"
@@ -18353,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"
@@ -18548,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)"
@@ -18572,6 +18788,10 @@ msgstr "tanımlanamayan %%(%s) argümanı: %s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "pozitif genişlik %%(align) ögeciği ile birlikte bekleniyordu"
 
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "beklenen biçim: %%(ahead-behind:<işlememsi>)"
+
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "hatalı oluşturulmuş alan adı: %.*s"
@@ -18618,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)"
@@ -18679,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"
@@ -19120,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'"
@@ -19193,10 +19422,6 @@ msgstr "'%s' içindeki çakışan durum güncellenemedi"
 msgid "no remembered resolution for '%s'"
 msgstr "'%s' için hatırlanan çözüm yok"
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "'%s' bağlantısı kesilemiyor"
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "'%s' için öngörüntü güncellendi"
@@ -19237,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"
 
@@ -19530,10 +19759,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "'%s' kilitlenemedi"
 
-#, c-format
-msgid "could not write to '%s'"
-msgstr "şuraya yazılamadı: '%s'"
-
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "satır sonu şuraya yazılamadı: '%s'"
@@ -19894,9 +20119,6 @@ msgstr "\"git cherry-pick (--continue | %s--abort | --quit)\" deneyin"
 msgid "could not create sequencer directory '%s'"
 msgstr "ardıştırıcı dizini '%s' oluşturulamadı"
 
-msgid "could not lock HEAD"
-msgstr "HEAD kilitlenemedi"
-
 msgid "no cherry-pick or revert in progress"
 msgstr "süren bir seç-al veya geri al yok"
 
@@ -19991,20 +20213,20 @@ msgstr ""
 "\tgit rebase --continue\n"
 "\n"
 
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "ve indekse ve/veya çalışma ağacına değişiklikler yapıldı\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "ve indekse ve/veya çalışma ağacına değişiklikler yapıldı.\n"
 
 #, 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 ""
-"Yürütme başarılı oldu: %s,\n"
-"ancak indeksinize ve/veya çalışma ağacınıza değişiklikler bıraktı\n"
+"Yürütme başarılı oldu: %s;\n"
+"ancak indeksinize ve/veya çalışma ağacınıza değişiklikler bıraktı.\n"
 "Değişikliklerinizi işleyin veya zulalayın, ardından şunu çalıştırın:\n"
 "\n"
 "\tgit rebase --continue\n"
@@ -20386,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)"
@@ -20437,10 +20730,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u bayt/sn"
 msgstr[1] "%u bayt/sn"
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr "'%s' düzenlenemedi"
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "kuşku doğuran altmodül yok sayılıyor: %s"
@@ -22147,12 +22436,16 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) '%s' yürütülemedi"
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) %s: %s, '%s' konumundan ekleniyor\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) '%s' ögesinden hatalı oluşturulmuş çıktı"
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
-msgstr "(%s) şuraya olan veri yolu kapatılamadı: '%s'"
+msgstr "(%s) şuraya olan veriyolu kapatılamadı: '%s'"
+
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) %s: %s, '%s' konumundan ekleniyor\n"
 
 msgid "cannot send message as 7bit"
 msgstr "ileti 7 bit olarak gönderilemiyor"
diff --git a/po/uk.po b/po/uk.po
new file mode 100644 (file)
index 0000000..5a11cc6
--- /dev/null
+++ b/po/uk.po
@@ -0,0 +1,22768 @@
+# Ukrainian translation for Git package.
+# Український переклад пакету Git.
+# Copyright (c) 2023 Arkadii Yakovets.
+# Copyright (c) 2023 Kateryna Golovanova.
+# This file is distributed under the same license as the Git package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Git v2.42.0\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\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-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.2\n"
+
+#, c-format
+msgid "Huh (%s)?"
+msgstr "Га (%s)?"
+
+msgid "could not read index"
+msgstr "не вдалося прочитати індекс"
+
+msgid "binary"
+msgstr "бінарний"
+
+msgid "nothing"
+msgstr "нічого"
+
+msgid "unchanged"
+msgstr "без змін"
+
+msgid "Update"
+msgstr "Оновити"
+
+#, c-format
+msgid "could not stage '%s'"
+msgstr "не вдалося додати до індексу %s"
+
+msgid "could not write index"
+msgstr "не вдалося записати індекс"
+
+#, c-format
+msgid "updated %d path\n"
+msgid_plural "updated %d paths\n"
+msgstr[0] "оновлено %d шлях\n"
+msgstr[1] "оновлено %d шляхи\n"
+msgstr[2] "оновлено %d шляхів\n"
+
+#, c-format
+msgid "note: %s is untracked now.\n"
+msgstr "примітка: %s зараз не відстежується.\n"
+
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr "невдала спроба make_cache_entry для шляху \"%s\""
+
+msgid "Revert"
+msgstr "Вивернути"
+
+msgid "Could not parse HEAD^{tree}"
+msgstr "Не вдалося розібрати HEAD^{tree}"
+
+#, c-format
+msgid "reverted %d path\n"
+msgid_plural "reverted %d paths\n"
+msgstr[0] "вивернуто %d шлях\n"
+msgstr[1] "вивернуто %d шляхи\n"
+msgstr[2] "вивернуто %d шляхів\n"
+
+#, c-format
+msgid "No untracked files.\n"
+msgstr "Невідстежуваних файлів немає\n"
+
+msgid "Add untracked"
+msgstr "Додати невідстежувані"
+
+#, c-format
+msgid "added %d path\n"
+msgid_plural "added %d paths\n"
+msgstr[0] "додано %d шлях\n"
+msgstr[1] "додано %d шляхи\n"
+msgstr[2] "додано %d шляхів\n"
+
+#, c-format
+msgid "ignoring unmerged: %s"
+msgstr "ігноруються не злиті записи: %s"
+
+#, c-format
+msgid "Only binary files changed.\n"
+msgstr "Змінилися лише бінарні файли.\n"
+
+#, c-format
+msgid "No changes.\n"
+msgstr "Нічого не змінено.\n"
+
+msgid "Patch update"
+msgstr "Оновлення латки"
+
+msgid "Review diff"
+msgstr "Переглянути різницю"
+
+msgid "show paths with changes"
+msgstr "показати шляхи зі змінами"
+
+msgid "add working tree state to the staged set of changes"
+msgstr "додати стан робочого дерева до індексу"
+
+msgid "revert staged set of changes back to the HEAD version"
+msgstr "вивернути зміни індексу до версії HEAD"
+
+msgid "pick hunks and update selectively"
+msgstr "вибирати шматки і оновлювати вибірково"
+
+msgid "view diff between HEAD and index"
+msgstr "переглянути різницю між HEAD та індексом"
+
+msgid "add contents of untracked files to the staged set of changes"
+msgstr "додати вміст невідстежуваних файлів до індексу"
+
+msgid "Prompt help:"
+msgstr "Підказка по опціям:"
+
+msgid "select a single item"
+msgstr "вибрати один елемент"
+
+msgid "select a range of items"
+msgstr "вибрати діапазон елементів"
+
+msgid "select multiple ranges"
+msgstr "вибрати кілька діапазонів"
+
+msgid "select item based on unique prefix"
+msgstr "вибрати елемент за унікальним префіксом"
+
+msgid "unselect specified items"
+msgstr "зняти позначку із зазначених елементів"
+
+msgid "choose all items"
+msgstr "вибрати всі елементи"
+
+msgid "(empty) finish selecting"
+msgstr "(пусто) закінчити вибір"
+
+msgid "select a numbered item"
+msgstr "вибрати пронумерований елемент"
+
+msgid "(empty) select nothing"
+msgstr "(пусто) нічого не вибирати"
+
+msgid "*** Commands ***"
+msgstr "*** Команди ***"
+
+msgid "What now"
+msgstr "Що тепер"
+
+msgid "staged"
+msgstr "в індексі"
+
+msgid "unstaged"
+msgstr "поза індексом"
+
+msgid "path"
+msgstr "шлях"
+
+msgid "could not refresh index"
+msgstr "не вдалося оновити індекс"
+
+#, c-format
+msgid "Bye.\n"
+msgstr "До побачення.\n"
+
+#, c-format
+msgid "Stage mode change [y,n,q,a,d%s,?]? "
+msgstr "Індексувати зміну режиму [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Stage deletion [y,n,q,a,d%s,?]? "
+msgstr "Індексувати видалення [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Stage addition [y,n,q,a,d%s,?]? "
+msgstr "Індексувати додавання [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Stage this hunk [y,n,q,a,d%s,?]? "
+msgstr "Індексувати цей шматок [y,n,q,a,d%s,?]? "
+
+msgid ""
+"If the patch applies cleanly, the edited hunk will immediately be marked for "
+"staging."
+msgstr ""
+"Якщо латка буде застосована без помилок, відредагований шматок буде одразу ж "
+"позначено для індексації."
+
+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\n"
+msgstr ""
+"y - індексувати цей шматок\n"
+"n - не індексувати цей шматок\n"
+"q - вийти; не індексувати ні цей шматок, ні решту\n"
+"a - індексувати цей шматок і всі наступні шматки у файлі\n"
+"d - не індексувати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Stash mode change [y,n,q,a,d%s,?]? "
+msgstr "Сховати зміну режиму [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Stash deletion [y,n,q,a,d%s,?]? "
+msgstr "Сховати видалення [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Stash addition [y,n,q,a,d%s,?]? "
+msgstr "Сховати додавання [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Stash this hunk [y,n,q,a,d%s,?]? "
+msgstr "Сховати цей шматок [y,n,q,a,d%s,?]? "
+
+msgid ""
+"If the patch applies cleanly, the edited hunk will immediately be marked for "
+"stashing."
+msgstr ""
+"Якщо латка буде застосована без помилок, відредагований шматок буде одразу ж "
+"позначено для схову."
+
+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\n"
+msgstr ""
+"y - сховати цей шматок\n"
+"n - не ховати цей шматок\n"
+"q - вийти; не ховати ні цей шматок, ні решту\n"
+"a - сховати цей шматок і всі наступні шматки у файлі\n"
+"d - не ховати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Unstage mode change [y,n,q,a,d%s,?]? "
+msgstr "Прибрати з індексу зміну режиму [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Unstage deletion [y,n,q,a,d%s,?]? "
+msgstr "Прибрати з індексу видалення [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Unstage addition [y,n,q,a,d%s,?]? "
+msgstr "Прибрати з індексу додавання [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
+msgstr "Прибрати з індексу цей шматок [y,n,q,a,d%s,?]? "
+
+msgid ""
+"If the patch applies cleanly, the edited hunk will immediately be marked for "
+"unstaging."
+msgstr ""
+"Якщо латка буде застосована без помилок, відредагований шматок буде одразу ж "
+"позначено для розіндексації."
+
+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\n"
+msgstr ""
+"y - прибрати з індексу цей шматок\n"
+"n - не прибирати з індексу цей шматок\n"
+"q - вийти; не прибирати з індексу ні цей шматок, ні решту\n"
+"a - прибрати з індексу цей шматок і всі наступні шматки у файлі\n"
+"d - не прибирати з індексу цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
+msgstr "Застосувати зміну режиму до індексу [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
+msgstr "Застосувати видалення до індексу [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply addition to index [y,n,q,a,d%s,?]? "
+msgstr "Застосувати додавання до індексу [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
+msgstr "Застосувати цей шматок до індексу [y,n,q,a,d%s,?]? "
+
+msgid ""
+"If the patch applies cleanly, the edited hunk will immediately be marked for "
+"applying."
+msgstr ""
+"Якщо латка буде застосована без помилок, відредагований шматок буде одразу ж "
+"позначено для застосування."
+
+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\n"
+msgstr ""
+"y - застосувати цей шматок до індексу\n"
+"n - не застосовувати цей шматок до індексу\n"
+"q - вийти; не застосовувати ні цей шматок, ні решту\n"
+"a - застосувати цей шматок і всі наступні шматки у файлі\n"
+"d - не застосовувати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути зміну режиму з робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути видалення з робочого дерева [y,n,q,a,d%s,?] "
+
+#, c-format
+msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути додавання з робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути цей шматок з робочого дерева [y,n,q,a,d%s,?]? "
+
+msgid ""
+"If the patch applies cleanly, the edited hunk will immediately be marked for "
+"discarding."
+msgstr ""
+"Якщо латка буде застосована без помилок, відредагований шматок буде одразу ж "
+"позначено для відкидання."
+
+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\n"
+msgstr ""
+"y - відкинути цей шматок з робочого дерева\n"
+"n - не відкидати цей шматок з робочого дерева\n"
+"q - вийти; не відкидати ні цей шматок, ні решту\n"
+"a - відкинути цей шматок і всі наступні шматки у файлі\n"
+"d - не відкидати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути зміну режиму з індексу та робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути видалення з індексу та робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути додавання з індексу та робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Відкинути цей шматок з індексу та робочого дерева [y,n,q,a,d%s,?]? "
+
+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\n"
+msgstr ""
+"y - відкинути цей шматок з індексу та робочого дерева\n"
+"n - не відкидати цей шматок з індексу та робочого дерева\n"
+"q - вийти; не відкидати ні цей шматок, ні решту\n"
+"a - відкинути цей шматок і всі наступні шматки у файлі\n"
+"d - не відкидати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+"Застосувати зміну режиму до індексу та робочого дерева [y,n,q,a,d%s,?] "
+
+#, c-format
+msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Застосувати видалення до індексу та робочого дерева [y,n,q,a,d%s,?] "
+
+#, c-format
+msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Застосувати додавання до індексу та робочого дерева [y,n,q,a,d%s,?] "
+
+#, c-format
+msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Застосувати цей шматок до індексу та робочого дерева [y,n,q,a,d%s,?] "
+
+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\n"
+msgstr ""
+"y - застосувати цей шматок до індексу та робочого дерева\n"
+"n - не застосовувати цей шматок до індексу та робочого дерева\n"
+"q - вийти; не застосовувати ні цей шматок, ні решту\n"
+"a - застосувати цей шматок і всі наступні шматки у файлі\n"
+"d - не застосовувати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Застосувати зміну режиму до робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Застосувати видалення до робочого дерева [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Застосувати додавання до робочого дерева [y,n,q,a,d%s,?]? "
+
+#, 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"
+"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\n"
+msgstr ""
+"y - застосувати цей шматок до робочого дерева\n"
+"n - не застосовувати цей шматок до робочого дерева\n"
+"q - вийти; не застосовувати ні цей шматок, ні решту\n"
+"a - застосувати цей шматок і всі наступні шматки у файлі\n"
+"d - не застосовувати цей шматок і всі наступні шматки у файлі\n"
+
+#, c-format
+msgid "could not parse hunk header '%.*s'"
+msgstr "не вдалося розібрати заголовок шматка \"%.*s\""
+
+msgid "could not parse diff"
+msgstr "не вдалося розібрати різницю"
+
+msgid "could not parse colored diff"
+msgstr "не вдалося розібрати кольоровану різницю"
+
+#, c-format
+msgid "failed to run '%s'"
+msgstr "не вдалося запустити \"%s\""
+
+msgid "mismatched output from interactive.diffFilter"
+msgstr "неспівпадіння виводу з interactive.diffFilter"
+
+msgid ""
+"Your filter must maintain a one-to-one correspondence\n"
+"between its input and output lines."
+msgstr ""
+"Ваш фільтр повинен підтримувати один до одного відповідність\n"
+"між його вхідними та вихідними рядками."
+
+#, c-format
+msgid ""
+"expected context line #%d in\n"
+"%.*s"
+msgstr ""
+"очікувався рядок контексту #%d в\n"
+"%.*s"
+
+#, c-format
+msgid ""
+"hunks do not overlap:\n"
+"%.*s\n"
+"\tdoes not end with:\n"
+"%.*s"
+msgstr ""
+"шматки не перетинаються:\n"
+"%.*s\n"
+"\tне закінчується на:\n"
+"%.*s"
+
+msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
+msgstr "Режим ручного редагування шматка -- див. короткий посібник внизу.\n"
+
+#, c-format
+msgid ""
+"---\n"
+"To remove '%c' lines, make them ' ' lines (context).\n"
+"To remove '%c' lines, delete them.\n"
+"Lines starting with %c will be removed.\n"
+msgstr ""
+"---\n"
+"Щоб видалити рядки \"%c\", зробіть їх рядками \" \" (контекст).\n"
+"Щоб видалити рядки \"%c\", вилучіть їх.\n"
+"Буде видалено рядки, що починаються з %c.\n"
+
+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"
+"aborted and the hunk is left unchanged.\n"
+msgstr ""
+"Якщо шматок буде застосований з помилками, вам буде надана можливість\n"
+"відредагувати ще раз.  Якщо всі рядки шматка буде вилучено, то редагування "
+"буде\n"
+"перервано, і шматок залишиться без змін.\n"
+
+msgid "could not parse hunk header"
+msgstr "не вдалося розібрати заголовок шматка"
+
+msgid "'git apply --cached' failed"
+msgstr "\"git apply --cached\" завершився невдало"
+
+#. 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 ""
+"Ваш відредагований шматок неможливо застосувати. Відредагувати ще раз "
+"(\"no\" - відкинути!) [y/n]? "
+
+msgid "The selected hunks do not apply to the index!"
+msgstr "Вибрані шматки неможливо застосувати до індексу!"
+
+msgid "Apply them to the worktree anyway? "
+msgstr "Все одно застосувати їх до робочого дерева? "
+
+msgid "Nothing was applied.\n"
+msgstr "Нічого не застосовано.\n"
+
+msgid ""
+"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"
+"g - select a hunk to go to\n"
+"/ - search for a hunk matching the given regex\n"
+"s - split the current hunk into smaller hunks\n"
+"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 "Немає попереднього шматка"
+
+msgid "No next hunk"
+msgstr "Немає наступного шматка"
+
+msgid "No other hunks to goto"
+msgstr "Немає інших шматків для переходу"
+
+msgid "go to which hunk (<ret> to see more)? "
+msgstr "до якого шматка перейти (<ret>, щоб побачити більше)? "
+
+msgid "go to which hunk? "
+msgstr "до якого шматка перейти? "
+
+#, c-format
+msgid "Invalid number: '%s'"
+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 шматків."
+
+msgid "No other hunks to search"
+msgstr "Немає інших шматків для пошуку"
+
+msgid "search for regex? "
+msgstr "шукати регвир? "
+
+#, c-format
+msgid "Malformed search regexp %s: %s"
+msgstr "Невірно сформований регвир пошуку %s: %s"
+
+msgid "No hunk matches the given pattern"
+msgstr "Жоден шматок не відповідає заданому шаблону"
+
+msgid "Sorry, cannot split this hunk"
+msgstr "Вибачайте, не можу розщепити цей шматок"
+
+#, c-format
+msgid "Split into %d hunks."
+msgstr "Розщепити на %d шматків."
+
+msgid "Sorry, cannot edit this hunk"
+msgstr "Вибачайте, не можу редагувати цей шматок"
+
+msgid "'git apply' failed"
+msgstr "\"git apply\" завершився невдало"
+
+#, c-format
+msgid ""
+"\n"
+"Disable this message with \"git config advice.%s false\""
+msgstr ""
+"\n"
+"Вимкнути це повідомлення можна за допомогою \"git config advice.%s false\""
+
+#, c-format
+msgid "%shint: %.*s%s\n"
+msgstr "%sпідказка: %.*s%s\n"
+
+msgid "Cherry-picking is not possible because you have unmerged files."
+msgstr "Висмикування неможливе, оскільки у вас є не злиті файли."
+
+msgid "Committing is not possible because you have unmerged files."
+msgstr "Створення коміту неможливе, оскільки у вас є не злиті файли."
+
+msgid "Merging is not possible because you have unmerged files."
+msgstr "Злиття неможливе, оскільки у вас є не злиті файли."
+
+msgid "Pulling is not possible because you have unmerged files."
+msgstr "Отримання неможливе, оскільки у вас є не злиті файли."
+
+msgid "Reverting is not possible because you have unmerged files."
+msgstr "Вивертання неможливе, оскільки у вас є не злиті файли."
+
+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 ""
+"Виправте їх у робочому дереві, а потім скористайтесь командою \"git add/rm "
+"<файл>\"\n"
+"щоб позначити вирішення і зробити коміт."
+
+msgid "Exiting because of an unresolved conflict."
+msgstr "Вихід через невирішений конфлікт."
+
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr "Ви не завершили злиття (існує MERGE_HEAD)."
+
+msgid "Please, commit your changes before merging."
+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 ""
+"Гілки, що розходяться, не можуть бути перемотані вперед, вам потрібно "
+"зробити:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"або\n"
+"\n"
+"\tgit rebase\n"
+
+msgid "Not possible to fast-forward, aborting."
+msgstr "Неможливо перемотати вперед, переривання."
+
+#, c-format
+msgid ""
+"The following paths and/or pathspecs matched paths that exist\n"
+"outside of your sparse-checkout definition, so will not be\n"
+"updated in the index:\n"
+msgstr ""
+"Наступні шляхи та/або визначники шляхів відповідають шляхам, які існують\n"
+"за межами визначення вашого розрідженого переходу, тому не будуть\n"
+"оновлені в індексі:\n"
+
+msgid ""
+"If you intend to update such entries, try one of the following:\n"
+"* Use the --sparse option.\n"
+"* Disable or modify the sparsity rules."
+msgstr ""
+"Якщо ви маєте намір оновити такі записи, спробуйте один із наведених нижче "
+"способів:\n"
+"* Використайте параметр --sparse.\n"
+"* Вимкніть або змініть правила розрідженості."
+
+#, c-format
+msgid ""
+"Note: switching to '%s'.\n"
+"\n"
+"You are in 'detached HEAD' state. You can look around, make experimental\n"
+"changes and commit them, and you can discard any commits you make in this\n"
+"state without impacting any branches by switching back to a branch.\n"
+"\n"
+"If you want to create a new branch to retain commits you create, you may\n"
+"do so (now or later) by using -c with the switch command. Example:\n"
+"\n"
+"  git switch -c <new-branch-name>\n"
+"\n"
+"Or undo this operation with:\n"
+"\n"
+"  git switch -\n"
+"\n"
+"Turn off this advice by setting config variable advice.detachedHead to "
+"false\n"
+"\n"
+msgstr ""
+"Примітка: перемикання на \"%s\".\n"
+"\n"
+"Ви перебуваєте в стані \"відʼєднаного HEAD\". Ви можете озирнутися довкола, "
+"внести експериментальні\n"
+"зміни і зробити коміт, також ви можете відкинути будь-які коміти, зроблені у "
+"цьому\n"
+"стані, не впливаючи на інші гілки, просто перейшовши до іншої гілки.\n"
+"\n"
+"Якщо ви хочете створити нову гілку для збереження зроблених вами комітів, ви "
+"можете\n"
+"використати (зараз або пізніше) -c з командою switch. Наприклад:\n"
+"\n"
+"  git switch -c <назва-нової-гілки\n"
+"\n"
+"Або скасувати цю операцію за допомогою:\n"
+"\n"
+"  git switch -\n"
+"\n"
+"Щоб вимкнути цю пораду, встановіть конфігураційний параметр advice."
+"detachedHead у false\n"
+
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Наступні шляхи, що було винесено за межі визначення розрідженого\n"
+"переходу, не є розрідженими через локальні\n"
+"зміни.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Щоб виправити розрідженість цих шляхів, виконайте наступне:\n"
+"* Використайте \"git add --sparse <шляхи>\" для оновлення індексу\n"
+"* Використайте \"git sparse-checkout reapply\", щоб застосувати правила "
+"розрідженості"
+
+msgid "cmdline ends with \\"
+msgstr "cmdline завершується символом \\"
+
+msgid "unclosed quote"
+msgstr "незакриті лапки"
+
+msgid "too many arguments"
+msgstr "забагато аргументів"
+
+#, c-format
+msgid "unrecognized whitespace option '%s'"
+msgstr "нерозпізнана опція пробільних символів \"%s\""
+
+#, c-format
+msgid "unrecognized whitespace ignore option '%s'"
+msgstr "нерозпізнана опція ігнорування пробільних символів \"%s\""
+
+#, c-format
+msgid "options '%s' and '%s' cannot be used together"
+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"
+
+#, c-format
+msgid "regexec returned %d for input: %s"
+msgstr "regexec повернув %d для вводу: %s"
+
+#, c-format
+msgid "unable to find filename in patch at line %d"
+msgstr "не вдалося знайти назву файла в рядку %d латки"
+
+#, c-format
+msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
+msgstr ""
+"git apply: невірний git-diff - очікувалось /dev/null, отримано %s у рядку %d"
+
+#, c-format
+msgid "git apply: bad git-diff - inconsistent new filename on line %d"
+msgstr ""
+"git apply: невірний git-diff - невідповідна назва нового файлу в рядку %d"
+
+#, c-format
+msgid "git apply: bad git-diff - inconsistent old filename on line %d"
+msgstr ""
+"git apply: невірний git-diff - невідповідна назва старого файлу в рядку %d"
+
+#, c-format
+msgid "git apply: bad git-diff - expected /dev/null on line %d"
+msgstr "git apply: невірний git-diff - очікувалось /dev/null у рядку %d"
+
+#, c-format
+msgid "invalid mode on line %d: %s"
+msgstr "неприпустимий режим у рядку %d: %s"
+
+#, c-format
+msgid "inconsistent header lines %d and %d"
+msgstr "невідповідні рядки заголовка %d та %d"
+
+#, c-format
+msgid ""
+"git diff header lacks filename information when removing %d leading pathname "
+"component (line %d)"
+msgid_plural ""
+"git diff header lacks filename information when removing %d leading pathname "
+"components (line %d)"
+msgstr[0] ""
+"у заголовку git diff відсутня інформація про назву файла при видаленні %d "
+"провідного компонента назви шляху (рядок %d)"
+msgstr[1] ""
+"у заголовку git diff відсутня інформація про назву файла при видаленні %d "
+"провідних компонентів назви шляху (рядок %d)"
+msgstr[2] ""
+"у заголовку git diff відсутня інформація про назву файла при видаленні %d "
+"провідних компонентів назви шляху (рядок %d)"
+
+#, c-format
+msgid "git diff header lacks filename information (line %d)"
+msgstr "у заголовку git diff відсутня інформація про назву файла (рядок %d)"
+
+#, c-format
+msgid "recount: unexpected line: %.*s"
+msgstr "recount: неочікуваний рядок: %.*s"
+
+#, c-format
+msgid "patch fragment without header at line %d: %.*s"
+msgstr "фрагмент латки без заголовка у рядку %d: %.*s"
+
+msgid "new file depends on old contents"
+msgstr "новий файл залежить від старого вмісту"
+
+msgid "deleted file still has contents"
+msgstr "видалений файл все ще має вміст"
+
+#, c-format
+msgid "corrupt patch at line %d"
+msgstr "пошкоджена латка у рядку %d"
+
+#, c-format
+msgid "new file %s depends on old contents"
+msgstr "новий файл %s залежить від старого вмісту"
+
+#, c-format
+msgid "deleted file %s still has contents"
+msgstr "видалений файл %s все ще має вміст"
+
+#, c-format
+msgid "** warning: file %s becomes empty but is not deleted"
+msgstr "** попередження: файл %s стане порожнім, але не буде видалений"
+
+#, c-format
+msgid "corrupt binary patch at line %d: %.*s"
+msgstr "пошкоджена бінарна латка у рядку %d: %.*s"
+
+#, c-format
+msgid "unrecognized binary patch at line %d"
+msgstr "нерозпізнана бінарна латка у рядку %d"
+
+#, c-format
+msgid "patch with only garbage at line %d"
+msgstr "латка, що містить лише непотріб у рядку %d"
+
+#, c-format
+msgid "unable to read symlink %s"
+msgstr "не вдалося прочитати символьне посилання %s"
+
+#, c-format
+msgid "unable to open or read %s"
+msgstr "не вдалося відкрити або прочитати %s"
+
+#, c-format
+msgid "invalid start of line: '%c'"
+msgstr "неприпустимий початок рядка: \"%c\""
+
+#, c-format
+msgid "Hunk #%d succeeded at %d (offset %d line)."
+msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
+msgstr[0] "Шматок #%d успішно застосовано на позиції %d (зміщення %d рядок)."
+msgstr[1] "Шматок #%d успішно застосовано на позиції %d (зміщення %d рядки)."
+msgstr[2] "Шматок #%d успішно застосовано на позиції %d (зміщення %d рядків)."
+
+#, c-format
+msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
+msgstr ""
+"Контекст скорочено до (%ld/%ld), щоб застосувати фрагмент на позиції %d"
+
+#, c-format
+msgid ""
+"while searching for:\n"
+"%.*s"
+msgstr ""
+"поки йде пошук:\n"
+"%.*s"
+
+#, c-format
+msgid "missing binary patch data for '%s'"
+msgstr "відсутні дані бінарної латки для \"%s\""
+
+#, c-format
+msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'"
+msgstr ""
+"неможливо виконати reverse-apply бінарної латки без зворотнього шматка до "
+"\"%s\""
+
+#, c-format
+msgid "cannot apply binary patch to '%s' without full index line"
+msgstr ""
+"неможливо застосувати бінарну латку до \"%s\" без повного індексного рядка"
+
+#, c-format
+msgid ""
+"the patch applies to '%s' (%s), which does not match the current contents."
+msgstr ""
+"латка застосовується до \"%s\" (%s), який не збігається з поточним вмістом."
+
+#, c-format
+msgid "the patch applies to an empty '%s' but it is not empty"
+msgstr "латка застосовується до порожнього \"%s\", який не є порожнім"
+
+#, c-format
+msgid "the necessary postimage %s for '%s' cannot be read"
+msgstr "неможливо прочитати необхідний postimage %s для \"%s\""
+
+#, c-format
+msgid "binary patch does not apply to '%s'"
+msgstr "бінарна латка не застосовується до \"%s\""
+
+#, c-format
+msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
+msgstr ""
+"бінарна латка для \"%s\" призводить до некоректного результату (очікувалось "
+"%s, отримано %s)"
+
+#, c-format
+msgid "patch failed: %s:%ld"
+msgstr "латання не вдалося: %s:%ld"
+
+#, c-format
+msgid "cannot checkout %s"
+msgstr "неможливо переключити стан %s"
+
+#, c-format
+msgid "failed to read %s"
+msgstr "не вдалося прочитати %s"
+
+#, c-format
+msgid "reading from '%s' beyond a symbolic link"
+msgstr "читання з \"%s\" за символьним посиланням"
+
+#, c-format
+msgid "path %s has been renamed/deleted"
+msgstr "шлях %s перейменовано/видалено"
+
+#, c-format
+msgid "%s: does not exist in index"
+msgstr "%s: не існує в індексі"
+
+#, c-format
+msgid "%s: does not match index"
+msgstr "%s: не співпадає з індексом"
+
+msgid "repository lacks the necessary blob to perform 3-way merge."
+msgstr ""
+"у сховищі відсутній необхідний blob для виконання тристороннього злиття."
+
+#, c-format
+msgid "Performing three-way merge...\n"
+msgstr "Виконання тристороннього злиття...\n"
+
+#, c-format
+msgid "cannot read the current contents of '%s'"
+msgstr "неможливо прочитати поточний вміст \"%s\""
+
+#, c-format
+msgid "Failed to perform three-way merge...\n"
+msgstr "Не вдалося виконати тристороннє злиття...\n"
+
+#, c-format
+msgid "Applied patch to '%s' with conflicts.\n"
+msgstr "Латка до \"%s\" застосована з конфліктами.\n"
+
+#, c-format
+msgid "Applied patch to '%s' cleanly.\n"
+msgstr "Латка до \"%s\" застосована чисто.\n"
+
+#, c-format
+msgid "Falling back to direct application...\n"
+msgstr "Повернення до прямого застосування...\n"
+
+msgid "removal patch leaves file contents"
+msgstr "латка видалення залишає вміст файлу"
+
+#, c-format
+msgid "%s: wrong type"
+msgstr "%s: невірний тип"
+
+#, c-format
+msgid "%s has type %o, expected %o"
+msgstr "%s має тип %o, очікувалось %o"
+
+#, c-format
+msgid "invalid path '%s'"
+msgstr "неприпустимий шлях \"%s\""
+
+#, c-format
+msgid "%s: already exists in index"
+msgstr "%s: вже існує в індексі"
+
+#, c-format
+msgid "%s: already exists in working directory"
+msgstr "%s: вже існує в робочій директорії"
+
+#, c-format
+msgid "new mode (%o) of %s does not match old mode (%o)"
+msgstr "новий режим (%o) для %s не відповідає старому режиму (%o)"
+
+#, c-format
+msgid "new mode (%o) of %s does not match old mode (%o) of %s"
+msgstr "новий режим (%o) для %s не відповідає старому режиму (%o) для %s"
+
+#, c-format
+msgid "affected file '%s' is beyond a symbolic link"
+msgstr "уражений файл \"%s\" знаходиться за межами символічного посилання"
+
+#, c-format
+msgid "%s: patch does not apply"
+msgstr "%s: латка не може бути застосована"
+
+#, c-format
+msgid "Checking patch %s..."
+msgstr "Перевірка латки %s..."
+
+#, c-format
+msgid "sha1 information is lacking or useless for submodule %s"
+msgstr "sha1 інформація відсутня або марна для підмодуля %s"
+
+#, c-format
+msgid "mode change for %s, which is not in current HEAD"
+msgstr "зміна режиму для %s, якого немає в поточному HEAD"
+
+#, c-format
+msgid "sha1 information is lacking or useless (%s)."
+msgstr "sha1 інформація відсутня або марна (%s)."
+
+#, c-format
+msgid "could not add %s to temporary index"
+msgstr "не вдалося додати %s до тимчасового індексу"
+
+#, c-format
+msgid "could not write temporary index to %s"
+msgstr "не вдалося записати тимчасовий індекс у %s"
+
+#, c-format
+msgid "unable to remove %s from index"
+msgstr "не вдалося видалити %s з індексу"
+
+#, c-format
+msgid "corrupt patch for submodule %s"
+msgstr "пошкоджена латка для підмодуля %s"
+
+#, c-format
+msgid "unable to stat newly created file '%s'"
+msgstr "не вдалося отримати інформацію про щойно створений файл \"%s\""
+
+#, c-format
+msgid "unable to create backing store for newly created file %s"
+msgstr "не вдалося зробити запис для щойно створеного файлу %s"
+
+#, c-format
+msgid "unable to add cache entry for %s"
+msgstr "не вдалося додати запис кешу для %s"
+
+#, c-format
+msgid "failed to write to '%s'"
+msgstr "не вдалося записати в \"%s\""
+
+#, c-format
+msgid "closing file '%s'"
+msgstr "закриття файлу \"%s\""
+
+#, c-format
+msgid "unable to write file '%s' mode %o"
+msgstr "не вдалося записати файл \"%s\" в режимі %o"
+
+#, c-format
+msgid "Applied patch %s cleanly."
+msgstr "Латка %s застосована чисто."
+
+msgid "internal error"
+msgstr "внутрішня помилка"
+
+#, c-format
+msgid "Applying patch %%s with %d reject..."
+msgid_plural "Applying patch %%s with %d rejects..."
+msgstr[0] "Застосування латки %%s з %d відкиданням..."
+msgstr[1] "Застосування латки %%s з %d відкиданнями..."
+msgstr[2] "Застосування латки %%s з %d відкиданнями..."
+
+#, c-format
+msgid "truncating .rej filename to %.*s.rej"
+msgstr "скорочення назви файлу .rej до %.*s.rej"
+
+#, c-format
+msgid "cannot open %s"
+msgstr "неможливо відкрити %s"
+
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "неможливо видалити \"%s\""
+
+#, c-format
+msgid "Hunk #%d applied cleanly."
+msgstr "Шматок #%d застосовано чисто."
+
+#, c-format
+msgid "Rejected hunk #%d."
+msgstr "Шматок #%d відкинуто."
+
+#, c-format
+msgid "Skipped patch '%s'."
+msgstr "Пропущена латка \"%s\"."
+
+msgid "No valid patches in input (allow with \"--allow-empty\")"
+msgstr "Немає коректних латок на вході (дозволити через \"--allow-empty\")"
+
+msgid "unable to read index file"
+msgstr "не вдалося прочитати індексний файл"
+
+#, c-format
+msgid "can't open patch '%s': %s"
+msgstr "неможливо відкрити латку \"%s\": %s"
+
+#, c-format
+msgid "squelched %d whitespace error"
+msgid_plural "squelched %d whitespace errors"
+msgstr[0] "ігнорована %d помилка пробільних символів"
+msgstr[1] "ігноровані %d помилки пробільних символів"
+msgstr[2] "ігноровані %d помилок пробільних символів"
+
+#, c-format
+msgid "%d line adds whitespace errors."
+msgid_plural "%d lines add whitespace errors."
+msgstr[0] "%d рядок додає помилки пробільних символів."
+msgstr[1] "%d рядки додають помилки пробільних символів."
+msgstr[2] "%d рядків додають помилки пробільних символів."
+
+#, c-format
+msgid "%d line applied after fixing whitespace errors."
+msgid_plural "%d lines applied after fixing whitespace errors."
+msgstr[0] "%d рядок застосовано після виправлення помилок пробільних символів."
+msgstr[1] "%d рядки застосовано після виправлення помилок пробільних символів."
+msgstr[2] ""
+"%d рядків застосовано після виправлення помилок пробільних символів."
+
+msgid "Unable to write new index file"
+msgstr "Не вдалося записати новий файл індексу"
+
+msgid "don't apply changes matching the given path"
+msgstr "не застосовувати зміни, що відповідають вказаному шляху"
+
+msgid "apply changes matching the given path"
+msgstr "застосувати зміни, що відповідають вказаному шляху"
+
+msgid "num"
+msgstr "число"
+
+msgid "remove <num> leading slashes from traditional diff paths"
+msgstr "видалити <num> перших слешів з традиційних diff-шляхів"
+
+msgid "ignore additions made by the patch"
+msgstr "ігнорувати доповнення, зроблені латкою"
+
+msgid "instead of applying the patch, output diffstat for the input"
+msgstr "замість застосування латки вивести diffstat для вхідних даних"
+
+msgid "show number of added and deleted lines in decimal notation"
+msgstr "показати кількість доданих і видалених рядків у десятковій нотації"
+
+msgid "instead of applying the patch, output a summary for the input"
+msgstr "замість застосування латки вивести підсумок для вхідних даних"
+
+msgid "instead of applying the patch, see if the patch is applicable"
+msgstr "замість застосування латки перевірити можливість її застосування"
+
+msgid "make sure the patch is applicable to the current index"
+msgstr "переконатися, що латка може бути застосовна до поточного індексу"
+
+msgid "mark new files with `git add --intent-to-add`"
+msgstr "позначити нові файли командою \"git add --intent-to-add\""
+
+msgid "apply a patch without touching the working tree"
+msgstr "застосувати латку, не торкаючись робочого дерева"
+
+msgid "accept a patch that touches outside the working area"
+msgstr "прийняти латку, яка виходить за межі робочого простору"
+
+msgid "also apply the patch (use with --stat/--summary/--check)"
+msgstr "також застосувати латку (використовуйте з --stat/--summary/--check)"
+
+msgid "attempt three-way merge, fall back on normal patch if that fails"
+msgstr ""
+"спробувати тристороннє злиття, повернутися до звичайного латання, якщо це не "
+"вдасться"
+
+msgid "build a temporary index based on embedded index information"
+msgstr "створити тимчасовий індекс на основі вбудованої індексної інформації"
+
+msgid "paths are separated with NUL character"
+msgstr "шляхи відокремлюються символом NUL"
+
+msgid "ensure at least <n> lines of context match"
+msgstr "забезпечити збіг принаймні <n> рядків контексту"
+
+msgid "action"
+msgstr "дія"
+
+msgid "detect new or modified lines that have whitespace errors"
+msgstr "виявляти нові або змінені рядки з помилками пробільних символів"
+
+msgid "ignore changes in whitespace when finding context"
+msgstr "ігнорувати зміни пробільних символів при пошуку контексту"
+
+msgid "apply the patch in reverse"
+msgstr "застосувати латку у зворотному порядку"
+
+msgid "don't expect at least one line of context"
+msgstr "не очікувати на хоча б один рядок контексту"
+
+msgid "leave the rejected hunks in corresponding *.rej files"
+msgstr "залишити відкинуті шматки у відповідних *.rej файлах"
+
+msgid "allow overlapping hunks"
+msgstr "дозволити перекриття шматків"
+
+msgid "tolerate incorrectly detected missing new-line at the end of file"
+msgstr "дозволяти некоректно виявлену відсутність нового рядка в кінці файлу"
+
+msgid "do not trust the line counts in the hunk headers"
+msgstr "не довіряти кількості рядків у заголовках шматків"
+
+msgid "root"
+msgstr "корінь"
+
+msgid "prepend <root> to all filenames"
+msgstr "додати <корінь> до всіх назв файлів"
+
+msgid "don't return error for empty patches"
+msgstr "не повертати помилку для порожніх латок"
+
+#, c-format
+msgid "cannot stream blob %s"
+msgstr "неможливо транслювати blob %s"
+
+#, c-format
+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\" фільтр"
+
+msgid "unable to redirect descriptor"
+msgstr "не вдалося перенаправити дескриптор"
+
+#, c-format
+msgid "'%s' filter reported error"
+msgstr "Фільтр \"%s\" повідомив про помилку"
+
+#, c-format
+msgid "path is not valid UTF-8: %s"
+msgstr "шлях не є припустимим UTF-8: %s"
+
+#, c-format
+msgid "path too long (%d chars, SHA1: %s): %s"
+msgstr "шлях занадто довгий (%d символів, SHA1: %s): %s"
+
+#, c-format
+msgid "timestamp too large for this system: %<PRIuMAX>"
+msgstr "позначка часу занадто велика для цієї системи: %<PRIuMAX>"
+
+msgid "git archive [<options>] <tree-ish> [<path>...]"
+msgstr "git archive [<опції>] <деревоподібне-джерело> [<шлях>...]"
+
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
+msgstr ""
+"git archive --remote <сховище> [--exec <команда>] [<опції>] <деревоподібне-"
+"джерело> [<шлях>...]"
+
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr "git archive --remote <сховище> [--exec <команда>] --list"
+
+#, c-format
+msgid "cannot read '%s'"
+msgstr "неможливо прочитати \"%s\""
+
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "визначник шляху \"%s\" відповідає файлам поза поточною директорією"
+
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr "визначник шляxу \"%s\" не відповідає жодному файлу"
+
+#, c-format
+msgid "no such ref: %.*s"
+msgstr "немає такого посилання: %.*s"
+
+#, c-format
+msgid "not a valid object name: %s"
+msgstr "невірне ім’я об’єкта: %s"
+
+#, c-format
+msgid "not a tree object: %s"
+msgstr "не є об’єктом дерева: %s"
+
+#, c-format
+msgid "File not found: %s"
+msgstr "Файл не знайдено: %s"
+
+#, c-format
+msgid "Not a regular file: %s"
+msgstr "Не звичайний файл: %s"
+
+#, c-format
+msgid "unclosed quote: '%s'"
+msgstr "незакриті лапки: \"%s\""
+
+#, c-format
+msgid "missing colon: '%s'"
+msgstr "відсутня двокрапка: \"%s\""
+
+#, c-format
+msgid "empty file name: '%s'"
+msgstr "порожня назва файлу: \"%s\""
+
+msgid "fmt"
+msgstr "fmt"
+
+msgid "archive format"
+msgstr "формат архіву"
+
+msgid "prefix"
+msgstr "префікс"
+
+msgid "prepend prefix to each pathname in the archive"
+msgstr "додати префікс до кожної назви шляху в архіві"
+
+msgid "file"
+msgstr "файл"
+
+msgid "add untracked file to archive"
+msgstr "додати невідстежуваний файл до архіву"
+
+msgid "path:content"
+msgstr "шлях:вміст"
+
+msgid "write the archive to this file"
+msgstr "записати архів до цього файлу"
+
+msgid "read .gitattributes in working directory"
+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 "встановити рівень компресії"
+
+msgid "list supported archive formats"
+msgstr "показати список підтримуваних форматів архівів"
+
+msgid "repo"
+msgstr "сховище"
+
+msgid "retrieve the archive from remote repository <repo>"
+msgstr "отримати архів з віддаленого <сховища>"
+
+msgid "command"
+msgstr "команда"
+
+msgid "path to the remote git-upload-archive command"
+msgstr "шлях до віддаленої команди git-upload-archive"
+
+msgid "Unexpected option --remote"
+msgstr "Неочікувана опція --remote"
+
+#, c-format
+msgid "the option '%s' requires '%s'"
+msgstr "опція \"%s\" потребує \"%s\""
+
+msgid "Unexpected option --output"
+msgstr "Неочікувана опція --output"
+
+#, c-format
+msgid "Unknown archive format '%s'"
+msgstr "Невідомий формат архіву \"%s\""
+
+#, c-format
+msgid "Argument not supported for format '%s': -%d"
+msgstr "Аргумент не підтримується для формату \"%s\": -%d"
+
+#, c-format
+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 "ігнорування надто довгого рядка атрибутів %d"
+
+#, c-format
+msgid "%s not allowed: %s:%d"
+msgstr "%s не дозволено: %s:%d"
+
+msgid ""
+"Negative patterns are ignored in git attributes\n"
+"Use '\\!' for literal leading exclamation."
+msgstr ""
+"Негативні шаблони ігноруються в git атрибутах\n"
+"Використовуйте \"\\!\" для додання знака оклику."
+
+#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "неможливо виконати fstat для файла git атрибутів \"%s\""
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "ігнорування надто великого файлу gitattributes \"%s\""
+
+#, c-format
+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 "Подальше бісектування неможливо!\n"
+
+#, c-format
+msgid "Not a valid commit name %s"
+msgstr "Не є дійсною назвою коміту %s"
+
+#, c-format
+msgid ""
+"The merge base %s is bad.\n"
+"This means the bug has been fixed between %s and [%s].\n"
+msgstr ""
+"База злиття %s є невірною.\n"
+"Це означає, що помилку було виправлено між %s та [%s].\n"
+
+#, c-format
+msgid ""
+"The merge base %s is new.\n"
+"The property has changed between %s and [%s].\n"
+msgstr ""
+"База злиття %s є новою.\n"
+"Властивість змінилася між %s та [%s].\n"
+
+#, c-format
+msgid ""
+"The merge base %s is %s.\n"
+"This means the first '%s' commit is between %s and [%s].\n"
+msgstr ""
+"Базою злиття %s є %s.\n"
+"Це означає, що перший \"%s\" коміт знаходиться між %s і [%s].\n"
+
+#, c-format
+msgid ""
+"Some %s revs are not ancestors of the %s rev.\n"
+"git bisect cannot work properly in this case.\n"
+"Maybe you mistook %s and %s revs?\n"
+msgstr ""
+"Деякі %s revs не є предками %s rev.\n"
+"git bisect не може працювати належним чином в таких випадках.\n"
+"Можливо, ви переплутали %s і %s revs?\n"
+
+#, c-format
+msgid ""
+"the merge base between %s and [%s] must be skipped.\n"
+"So we cannot be sure the first %s commit is between %s and %s.\n"
+"We continue anyway."
+msgstr ""
+"базу злиття між %s і [%s] потрібно пропустити.\n"
+"Тому ми не можемо бути впевнені, що перший коміт %s знаходиться між %s і "
+"%s.\n"
+"Ми все одно продовжимо."
+
+#, c-format
+msgid "Bisecting: a merge base must be tested\n"
+msgstr "Бісекція: база злиття повинна бути протестована\n"
+
+#, c-format
+msgid "a %s revision is needed"
+msgstr "необхідна ревізія %s"
+
+#, c-format
+msgid "could not create file '%s'"
+msgstr "не вдалося створити файл \"%s\""
+
+#, c-format
+msgid "could not read file '%s'"
+msgstr "не вдалося прочитати файл \"%s\""
+
+msgid "reading bisect refs failed"
+msgstr "не вдалося прочитати бісекційні посилання"
+
+#, c-format
+msgid "%s was both %s and %s\n"
+msgstr "%s був одночасно і %s, і %s\n"
+
+#, c-format
+msgid ""
+"No testable commit found.\n"
+"Maybe you started with bad path arguments?\n"
+msgstr ""
+"Не знайдено коміт для тестування.\n"
+"Можливо, ви почали з невірних аргументів шляху?\n"
+
+#, c-format
+msgid "(roughly %d step)"
+msgid_plural "(roughly %d steps)"
+msgstr[0] "(приблизно %d крок)"
+msgstr[1] "(приблизно %d кроки)"
+msgstr[2] "(приблизно %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"
+msgstr[0] "Бісекція: залишилося протестувати %d ревізію після цього %s\n"
+msgstr[1] "Бісекція: залишилося протестувати %d ревізії після цього %s\n"
+msgstr[2] "Бісекція: залишилося протестувати %d ревізій після цього %s\n"
+
+msgid "--contents and --reverse do not blend well."
+msgstr "--contents і --reverse поєднуються не дуже добре."
+
+msgid "--reverse and --first-parent together require specified latest commit"
+msgstr "--reverse і --first-parent разом вимагають вказівки останнього коміту"
+
+msgid "revision walk setup failed"
+msgstr "не вдалося налаштувати проходження по ревізіям"
+
+msgid ""
+"--reverse --first-parent together require range along first-parent chain"
+msgstr ""
+"--reverse --first-parent разом вимагають вказівки діапазону вздовж ланцюжка "
+"першого батька"
+
+#, c-format
+msgid "no such path %s in %s"
+msgstr "немає шляху %s в %s"
+
+#, c-format
+msgid "cannot read blob %s for path %s"
+msgstr "неможливо прочитати blob %s для шляху %s"
+
+msgid ""
+"cannot inherit upstream tracking configuration of multiple refs when "
+"rebasing is requested"
+msgstr ""
+"неможливо успадкувати першоджерельну конфігурацію відстежування кількох "
+"посилань при запиті перебазування"
+
+#, c-format
+msgid "not setting branch '%s' as its own upstream"
+msgstr "гілку \"%s\" не встановлено власним першоджерельним сховищем"
+
+#, c-format
+msgid "branch '%s' set up to track '%s' by rebasing."
+msgstr "гілку \"%s\" налаштовано на відстежування \"%s\" через перебазування."
+
+#, c-format
+msgid "branch '%s' set up to track '%s'."
+msgstr "гілку \"%s\" налаштовано на відстежування \"%s\"."
+
+#, c-format
+msgid "branch '%s' set up to track:"
+msgstr "гілку \"%s\" налаштовано на відстежування:"
+
+msgid "unable to write upstream branch configuration"
+msgstr "не вдалося записати конфігурацію висхідної гілки"
+
+msgid ""
+"\n"
+"After fixing the error cause you may try to fix up\n"
+"the remote tracking information by invoking:"
+msgstr ""
+"\n"
+"Після усунення причини помилки ви можете спробувати виправити\n"
+"інформацію про віддалене відстежування здійснівши виклик:"
+
+#, c-format
+msgid "asked to inherit tracking from '%s', but no remote is set"
+msgstr ""
+"просили успадкувати відстежування з \"%s\", але віддалене призначення не "
+"встановлено"
+
+#, c-format
+msgid "asked to inherit tracking from '%s', but no merge configuration is set"
+msgstr ""
+"просили успадкувати відстежування з \"%s\", але конфігурацію злиття не задано"
+
+#, c-format
+msgid "not tracking: ambiguous information for ref '%s'"
+msgstr "не відстежується: неоднозначна інформація для посилання \"%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.
+#.
+#. 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"
+"tracking ref '%s':\n"
+"%s\n"
+"This is typically a configuration error.\n"
+"\n"
+"To support setting up tracking branches, ensure that\n"
+"different remotes' fetch refspecs map into different\n"
+"tracking namespaces."
+msgstr ""
+"Існує кілька віддалених призначень, визначники отримання посилань яких "
+"розвʼязуються у віддалено \n"
+"відстежуване посилання \"%s\":\n"
+"%s\n"
+"Зазвичай це помилка конфігурації.\n"
+"\n"
+"Щоб підтримувати налаштування гілок відстежування, переконайтеся, що\n"
+"визначники отримання посилань різних віддалених призначень розвʼязуються у "
+"різні\n"
+"простори імен відстежування."
+
+#, c-format
+msgid "'%s' is not a valid branch name"
+msgstr "\"%s\" не є допустимою назвою гілки"
+
+#, c-format
+msgid "a branch named '%s' already exists"
+msgstr "гілка з ім’ям \"%s\" вже існує"
+
+#, c-format
+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"
+msgstr ""
+"неможливо налаштувати інформацію про відстежування; початкова точка \"%s\" "
+"не є гілкою"
+
+#, c-format
+msgid "the requested upstream branch '%s' does not exist"
+msgstr "запитувана висхідна гілка \"%s\" не існує"
+
+msgid ""
+"\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push."
+msgstr ""
+"\n"
+"Якщо ви плануєте базувати свою роботу на основі першоджерельної\n"
+"гілки, яка вже існує на віддаленому призначенні, вам може знадобитися\n"
+"запустити \"git fetch\", щоб отримати її.\n"
+"\n"
+"Якщо ви плануєте надіслати нову локальну гілку, яка\n"
+"буде відстежувати свою віддалену гілку, вам слід скористатися командою\n"
+"\"git push -u\", щоб встановити конфігурацію першоджерельного сховища під "
+"час надсилання."
+
+#, c-format
+msgid "not a valid object name: '%s'"
+msgstr "не є допустимою назвою об’єкта: \"%s\""
+
+#, c-format
+msgid "ambiguous object name: '%s'"
+msgstr "неоднозначна назва об’єкта: \"%s\""
+
+#, c-format
+msgid "not a valid branch point: '%s'"
+msgstr "не є допустимою точкою розгалуження: \"%s\""
+
+#, c-format
+msgid "submodule '%s': unable to find submodule"
+msgstr "підмодуль \"%s\": не вдалося знайти підмодуль"
+
+#, c-format
+msgid ""
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
+msgstr ""
+"Ви можете спробувати оновити підмодулі за допомогою \"git checkout --no-"
+"recurse-submodules %s && git submodule update --init\"."
+
+#, c-format
+msgid "submodule '%s': cannot create branch '%s'"
+msgstr "підмодуль \"%s\": неможливо створити гілку \"%s\""
+
+#, c-format
+msgid "'%s' is already checked out at '%s'"
+msgstr "\"%s\" вже існує в \"%s\""
+
+msgid "git add [<options>] [--] <pathspec>..."
+msgstr "git add [<опції>] [--] <визначник шляху>..."
+
+#, c-format
+msgid "cannot chmod %cx '%s'"
+msgstr "неможливо виконати chmod %cx \"%s\""
+
+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 ""
+"параметр add.interactive.useBuiltin було видалено!\n"
+"Дивіться запис у \"git help config\" для більш детальної інформації."
+
+msgid "Could not read the index"
+msgstr "Не вдалося прочитати індекс"
+
+msgid "Could not write patch"
+msgstr "Не вдалося записати латку"
+
+msgid "editing patch failed"
+msgstr "не вдалося відредагувати латку"
+
+#, c-format
+msgid "Could not stat '%s'"
+msgstr "Не вдалося виконати stat \"%s\""
+
+msgid "Empty patch. Aborted."
+msgstr "Порожня латка. Перервано."
+
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "Не вдалося застосувати \"%s\""
+
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr "Наступні шляхи ігноруються одним з ваших .gitignore файлів:\n"
+
+msgid "dry run"
+msgstr "пробний запуск"
+
+msgid "be verbose"
+msgstr "розгорнутий вивід"
+
+msgid "interactive picking"
+msgstr "інтерактивний вибір"
+
+msgid "select hunks interactively"
+msgstr "обирати шматки інтерактивно"
+
+msgid "edit current diff and apply"
+msgstr "відредагувати поточну різницю і застосувати"
+
+msgid "allow adding otherwise ignored files"
+msgstr "дозволити додавання ігнорованих файлів"
+
+msgid "update tracked files"
+msgstr "оновити відстежувані файли"
+
+msgid "renormalize EOL of tracked files (implies -u)"
+msgstr "перенормувати EOL відстежуваних файлів (мається на увазі -u)"
+
+msgid "record only the fact that the path will be added later"
+msgstr "записати лише той факт, що шлях буде додано пізніше"
+
+msgid "add changes from all tracked and untracked files"
+msgstr "додати зміни з усіх відстежуваних і невідстежуваних файлів"
+
+msgid "ignore paths removed in the working tree (same as --no-all)"
+msgstr "ігнорувати шляхи, видалені у робочому дереві (те саме, що й --no-all)"
+
+msgid "don't add, only refresh the index"
+msgstr "не додавати, лише оновити індекс"
+
+msgid "just skip files which cannot be added because of errors"
+msgstr "просто пропустити файли, які не можуть бути додані через помилки"
+
+msgid "check if - even missing - files are ignored in dry run"
+msgstr ""
+"перевірити, чи ігноруються файли, навіть якщо вони відсутні, під час "
+"пробного запуску"
+
+msgid "allow updating entries outside of the sparse-checkout cone"
+msgstr "дозволити оновлення записів за межами конуса розрідженого переходу"
+
+msgid "override the executable bit of the listed files"
+msgstr "перевизначити біт виконання для зазначених файлів"
+
+msgid "warn when adding an embedded repository"
+msgstr "попереджувати при додаванні вбудованого сховища"
+
+#, c-format
+msgid ""
+"You've added another git repository inside your current repository.\n"
+"Clones of the outer repository will not contain the contents of\n"
+"the embedded repository and will not know how to obtain it.\n"
+"If you meant to add a submodule, use:\n"
+"\n"
+"\tgit submodule add <url> %s\n"
+"\n"
+"If you added this path by mistake, you can remove it from the\n"
+"index with:\n"
+"\n"
+"\tgit rm --cached %s\n"
+"\n"
+"See \"git help submodule\" for more information."
+msgstr ""
+"Ви додали ще одне git сховище всередині вашого поточного сховища.\n"
+"Клони зовнішнього сховища не міститимуть вмісту\n"
+"вбудованого сховища і не знатимуть, як його отримати.\n"
+"Якщо ви хочете додати підмодуль, скористайтесь командою\n"
+"\n"
+"\tgit submodule add <url> %s\n"
+"\n"
+"Якщо ви додали цей шлях помилково, ви можете видалити його з\n"
+"індексу за допомогою:\n"
+"\n"
+"\tgit rm --cached %s\n"
+"\n"
+"Докладніше дивіться у \"git help submodule\"."
+
+#, c-format
+msgid "adding embedded git repository: %s"
+msgstr "додавання вбудованого git сховища: %s"
+
+msgid ""
+"Use -f if you really want to add them.\n"
+"Turn this message off by running\n"
+"\"git config advice.addIgnoredFile false\""
+msgstr ""
+"Використовуйте -f, якщо ви дійсно хочете їх додати.\n"
+"Щоб вимкнути це повідомлення, виконайте\n"
+"\"git config advice.addIgnoredFile false\""
+
+msgid "adding files failed"
+msgstr "додавання файлів завершилося невдало"
+
+#, c-format
+msgid "--chmod param '%s' must be either -x or +x"
+msgstr "--chmod параметр \"%s\" має бути -x або +x"
+
+#, c-format
+msgid "'%s' and pathspec arguments cannot be used together"
+msgstr "\"%s\" та аргументи визначника шляху не можна використовувати разом"
+
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr "Нічого не зазначено, нічого не додано.\n"
+
+msgid ""
+"Maybe you wanted to say 'git add .'?\n"
+"Turn this message off by running\n"
+"\"git config advice.addEmptyPathspec false\""
+msgstr ""
+"Можливо, ви хотіли вказати \"git add .\"?\n"
+"Щоб вимкнути це повідомлення, виконайте\n"
+"\"git config advice.addEmptyPathspec false\""
+
+msgid "index file corrupt"
+msgstr "індексний файл пошкоджено"
+
+#, c-format
+msgid "bad action '%s' for '%s'"
+msgstr "невірна дія \"%s\" для \"%s\""
+
+#, c-format
+msgid "invalid value for '%s': '%s'"
+msgstr "неприпустиме значення для \"%s\": \"%s\""
+
+#, c-format
+msgid "could not read '%s'"
+msgstr "не вдалося прочитати \"%s\""
+
+msgid "could not parse author script"
+msgstr "не вдалося розібрати author script"
+
+#, c-format
+msgid "could not parse %s"
+msgstr "не вдалося розібрати %s"
+
+#, c-format
+msgid "'%s' was deleted by the applypatch-msg hook"
+msgstr "\"%s\" було видалено applypatch-msg гачком"
+
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr "Невірно сформований рядок вводу: \"%s\"."
+
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+msgstr "Не вдалося скопіювати нотатки з \"%s\" в \"%s\""
+
+msgid "fseek failed"
+msgstr "fseek завершився невдало"
+
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr "не вдалося відкрити \"%s\" для читання"
+
+#, c-format
+msgid "could not open '%s' for writing"
+msgstr "не вдалося відкрити \"%s\" для запису"
+
+#, c-format
+msgid "could not parse patch '%s'"
+msgstr "не вдалося розібрати латку \"%s\""
+
+msgid "Only one StGIT patch series can be applied at once"
+msgstr "Можна застосовувати лише одну серію StGIT латок одразу"
+
+msgid "invalid timestamp"
+msgstr "неприпустима позначка часу"
+
+msgid "invalid Date line"
+msgstr "неприпустимий рядок дати"
+
+msgid "invalid timezone offset"
+msgstr "неприпустиме зміщення часового поясу"
+
+msgid "Patch format detection failed."
+msgstr "Не вдалося визначити формат латки."
+
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr "не вдалося створити директорію \"%s\""
+
+msgid "Failed to split patches."
+msgstr "Не вдалося розщепити латки."
+
+#, c-format
+msgid "When you have resolved this problem, run \"%s --continue\"."
+msgstr "Коли ви вирішите цю проблему, виконайте \"%s --continue\"."
+
+#, c-format
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
+msgstr ""
+"Якщо ви бажаєте пропустити цю латку, виконайте \"%s --skip\" замість цього."
+
+#, c-format
+msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgstr ""
+"Щоб записати порожню латку як порожній коміт, виконайте \"%s --allow-empty\"."
+
+#, c-format
+msgid "To restore the original branch and stop patching, run \"%s --abort\"."
+msgstr ""
+"Щоб повернути гілку до початкового стану і зупинити латання, виконайте \"%s "
+"--abort\"."
+
+msgid "Patch sent with format=flowed; space at the end of lines might be lost."
+msgstr ""
+"Латку надіслано з параметром format=flowed; пробіли в кінці рядків можуть "
+"бути втрачені."
+
+#, c-format
+msgid "missing author line in commit %s"
+msgstr "відсутній рядок автора в коміті %s"
+
+#, c-format
+msgid "invalid ident line: %.*s"
+msgstr "неприпустимий ідентифікаційний рядок: %.*s"
+
+#, c-format
+msgid "unable to parse commit %s"
+msgstr "не вдалося розібрати коміт %s"
+
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr ""
+"У сховищі не вистачає необхідних blob-обʼєктів, щоб повернутися до "
+"тристороннього злиття."
+
+msgid "Using index info to reconstruct a base tree..."
+msgstr ""
+"Використання індексної інформації для реконструювання базового дерева..."
+
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+"Ви відредагували свою латку вручну?\n"
+"Це не стосується blob-обʼєктів, записаних у його індексі."
+
+msgid "Falling back to patching base and 3-way merge..."
+msgstr "Повернення до бази латки та тристороннього злиття..."
+
+msgid "Failed to merge in the changes."
+msgstr "Не вдалося злити зміни."
+
+msgid "git write-tree failed to write a tree"
+msgstr "git write-tree не вдалося записати дерево"
+
+msgid "applying to an empty history"
+msgstr "застосування до порожньої історії"
+
+msgid "failed to write commit object"
+msgstr "не вдалося записати об’єкт коміту"
+
+#, c-format
+msgid "cannot resume: %s does not exist."
+msgstr "неможливо продовжити: %s не існує."
+
+msgid "Commit Body is:"
+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 ""
+"Застосувати? [y]-так / [n]-ні / [e]-редагувати / [v]-переглянути латку / [a]-"
+"застосувати все: "
+
+msgid "unable to write index file"
+msgstr "не вдалося записати індексний файл"
+
+#, c-format
+msgid "Dirty index: cannot apply patches (dirty: %s)"
+msgstr "Індекс забруднено: неможливо застосувати латки (забруднено: %s)"
+
+#, c-format
+msgid "Skipping: %.*s"
+msgstr "Пропуск: %.*s"
+
+#, c-format
+msgid "Creating an empty commit: %.*s"
+msgstr "Створення порожнього коміту: %.*s"
+
+msgid "Patch is empty."
+msgstr "Латка порожня."
+
+#, c-format
+msgid "Applying: %.*s"
+msgstr "Застосування: %.*s"
+
+msgid "No changes -- Patch already applied."
+msgstr "Без змін - латку вже застосовано."
+
+#, c-format
+msgid "Patch failed at %s %.*s"
+msgstr "Латання не вдалося на %s %.*s"
+
+msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
+msgstr ""
+"Скористайтесь \"git am --show-current-patch=diff\", щоб побачити невдалу "
+"латку"
+
+msgid "No changes - recorded it as an empty commit."
+msgstr "Без змін - записаний як порожній коміт."
+
+msgid ""
+"No changes - did you forget to use 'git add'?\n"
+"If there is nothing left to stage, chances are that something else\n"
+"already introduced the same changes; you might want to skip this patch."
+msgstr ""
+"Без змін - ви забули використати \"git add\"?\n"
+"Якщо нічого індексувати, є ймовірність того, що хтось інший\n"
+"вже вніс ті самі зміни; можливо, ви захочете пропустити цю латку."
+
+msgid ""
+"You still have unmerged paths in your index.\n"
+"You should 'git add' each file with resolved conflicts to mark them as "
+"such.\n"
+"You might run `git rm` on a file to accept \"deleted by them\" for it."
+msgstr ""
+"У вашому індексі все ще залишаються не злиті шляхи.\n"
+"Вам слід виконати \"git add\" для кожного файлу з розвʼязаними конфліктами, "
+"щоб позначити їх як такі.\n"
+"Ви можете виконати \"git rm\" для файлу, щоб прийняти \"видалено ними\"."
+
+msgid "unable to write new index file"
+msgstr "не вдалося записати новий файл індексу"
+
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "Не вдалося розібрати об'єкт '%s'."
+
+msgid "failed to clean index"
+msgstr "не вдалося очистити індекс"
+
+msgid ""
+"You seem to have moved HEAD since the last 'am' failure.\n"
+"Not rewinding to ORIG_HEAD"
+msgstr ""
+"Здається, ви перемістили HEAD після останньої невдачі з \"am\".\n"
+"Перемотування вперед до ORIG_HEAD не виконується"
+
+#, c-format
+msgid "failed to read '%s'"
+msgstr "не вдалося прочитати \"%s\""
+
+#, c-format
+msgid "options '%s=%s' and '%s=%s' cannot be used together"
+msgstr "опції \"%s=%s\" and \"%s=%s\" не можна використовувати разом"
+
+msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
+msgstr "git am [<опції>] [(<скринька> [<поштова директорія>)...]"
+
+msgid "git am [<options>] (--continue | --skip | --abort)"
+msgstr "git am [<опції>] (--continue | --skip | --abort)"
+
+msgid "run interactively"
+msgstr "запустити інтерактивно"
+
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "обійти pre-applypatch та applypatch-msg гачки"
+
+msgid "historical option -- no-op"
+msgstr "стара опція -- не працює"
+
+msgid "allow fall back on 3way merging if needed"
+msgstr "дозволити повернутися до тристороннього злиття у разі потреби"
+
+msgid "be quiet"
+msgstr "працювати тихесенько"
+
+msgid "add a Signed-off-by trailer to the commit message"
+msgstr "додати Signed-off-by причіп у допис до коміту"
+
+msgid "recode into utf8 (default)"
+msgstr "перекодувати в utf8 (за замовчуванням)"
+
+msgid "pass -k flag to git-mailinfo"
+msgstr "передати -k прапорець до git-mailinfo"
+
+msgid "pass -b flag to git-mailinfo"
+msgstr "передати -b прапорець до git-mailinfo"
+
+msgid "pass -m flag to git-mailinfo"
+msgstr "передати -m прапорець до git-mailinfo"
+
+msgid "pass --keep-cr flag to git-mailsplit for mbox format"
+msgstr "передати --keep-cr прапорець до git-mailsplit для формату mbox"
+
+msgid "strip everything before a scissors line"
+msgstr "прибрати все раніше відрізної лінії"
+
+msgid "pass it through git-mailinfo"
+msgstr "передати через git-mailinfo"
+
+msgid "pass it through git-apply"
+msgstr "передати через git-apply"
+
+msgid "n"
+msgstr "н"
+
+msgid "format"
+msgstr "формат"
+
+msgid "format the patch(es) are in"
+msgstr "формат латки(-ок)"
+
+msgid "override error message when patch failure occurs"
+msgstr "перевизначити повідомлення про помилку при збої латання"
+
+msgid "continue applying patches after resolving a conflict"
+msgstr "продовжити застосування латки після вирішення конфлікту"
+
+msgid "synonyms for --continue"
+msgstr "те ж саме, що й --continue"
+
+msgid "skip the current patch"
+msgstr "пропустити поточну латку"
+
+msgid "restore the original branch and abort the patching operation"
+msgstr "відновити початкову гілку і перервати операцію латання"
+
+msgid "abort the patching operation but keep HEAD where it is"
+msgstr "перервати латання, але залишити HEAD на тому місці, де він знаходиться"
+
+msgid "show the patch being applied"
+msgstr "показати латку, що застосовується"
+
+msgid "record the empty patch as an empty commit"
+msgstr "записати порожню латку як порожній коміт"
+
+msgid "lie about committer date"
+msgstr "брехати про дату комітера"
+
+msgid "use current timestamp for author date"
+msgstr "використовувати поточну мітку часу для дати автора"
+
+msgid "key-id"
+msgstr "key-id"
+
+msgid "GPG-sign commits"
+msgstr "підписати коміти GPG-підписом"
+
+msgid "how to handle empty patches"
+msgstr "як обробляти порожні латки"
+
+msgid "(internal use for git-rebase)"
+msgstr "(внутрішнє використання для git-rebase)"
+
+msgid ""
+"The -b/--binary option has been a no-op for long time, and\n"
+"it will be removed. Please do not use it anymore."
+msgstr ""
+"Опція -b/--binary вже давно не працює і\n"
+"буде видалена. Будь ласка, не використовуйте її більше."
+
+msgid "failed to read the index"
+msgstr "не вдалося прочитати індекс"
+
+#, c-format
+msgid "previous rebase directory %s still exists but mbox given."
+msgstr ""
+"попередня директорія перебазування %s все ще існує, але було надано mbox."
+
+#, c-format
+msgid ""
+"Stray %s directory found.\n"
+"Use \"git am --abort\" to remove it."
+msgstr ""
+"Знайдено блукаючу директорію %s.\n"
+"скористайтесь командою \"git am --abort\", щоб вилучити її."
+
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr "Наразі не виконується операція вирішення, не поновлено."
+
+msgid "interactive mode requires patches on the command line"
+msgstr "інтерактивний режим потребує латки у командному рядку"
+
+msgid "git apply [<options>] [<patch>...]"
+msgstr "git apply [<опції>] [<латка>...]"
+
+msgid "could not redirect output"
+msgstr "неможливо перенаправити вивід"
+
+msgid "git archive: Remote with no URL"
+msgstr "git archive: віддалене призначення без URL"
+
+msgid "git archive: expected ACK/NAK, got a flush packet"
+msgstr "git archive: очікувалось ACK/NAK, отримано flush-пакет"
+
+#, c-format
+msgid "git archive: NACK %s"
+msgstr "git archive: NACK %s"
+
+msgid "git archive: protocol error"
+msgstr "git archive: помилка протоколу"
+
+msgid "git archive: expected a flush"
+msgstr "git archive: очікувалось flush"
+
+msgid ""
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
+msgstr ""
+"git bisect start [--term-{new,bad}=<термін> --term-{old,good}=<термін>]    "
+"[--no-checkout] [--first-parent] [<поганий> [<добрий>...]] [--]    "
+"[<визначник шляху>...]"
+
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (добрий|поганий) [<ревізія>...]"
+
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<ревізія>|<діапазон>)...]"
+
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<коміт>]"
+
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <лог файл>"
+
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <команда>..."
+
+#, c-format
+msgid "cannot open file '%s' in mode '%s'"
+msgstr "неможливо відкрити файл \"%s\" у режимі \"%s\""
+
+#, c-format
+msgid "could not write to file '%s'"
+msgstr "не вдалося записати в файл \"%s\""
+
+#, c-format
+msgid "cannot open file '%s' for reading"
+msgstr "неможливо відкрити файл \"%s\" для читання"
+
+#, c-format
+msgid "'%s' is not a valid term"
+msgstr "\"%s\" не є допустимим терміном"
+
+#, c-format
+msgid "can't use the builtin command '%s' as a term"
+msgstr "неможливо використати вбудовану команду \"%s\" як термін"
+
+#, c-format
+msgid "can't change the meaning of the term '%s'"
+msgstr "неможливо змінити значення терміну \"%s\""
+
+msgid "please use two different terms"
+msgstr "будь ласка, використовуйте два різних терміна"
+
+#, c-format
+msgid "We are not bisecting.\n"
+msgstr "Ми не робимо бісекцію.\n"
+
+#, c-format
+msgid "'%s' is not a valid commit"
+msgstr "\"%s\" не є дійсним комітом"
+
+#, c-format
+msgid ""
+"could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
+msgstr ""
+"не вдалося переключитися на початковий HEAD \"%s\". Спробуйте \"git bisect "
+"reset <коміт>\"."
+
+#, c-format
+msgid "Bad bisect_write argument: %s"
+msgstr "Невірний bisect_write аргумент: %s"
+
+#, c-format
+msgid "couldn't get the oid of the rev '%s'"
+msgstr "не вдалося отримати oid для rev \"%s\""
+
+#, c-format
+msgid "couldn't open the file '%s'"
+msgstr "не вдалося відкрити файл \"%s\""
+
+#, c-format
+msgid "Invalid command: you're currently in a %s/%s bisect"
+msgstr "Неприпустима команда: наразі ви в процесі %s/%s бісекції"
+
+#, c-format
+msgid ""
+"You need to give me at least one %s and %s revision.\n"
+"You can use \"git bisect %s\" and \"git bisect %s\" for that."
+msgstr ""
+"Ви маєте надати принаймні одну %s та %s ревізію.\n"
+"Для цього ви можете скористатися командами \"git bisect %s\" і \"git bisect "
+"%s\"."
+
+#, c-format
+msgid ""
+"You need to start by \"git bisect start\".\n"
+"You then need to give me at least one %s and %s revision.\n"
+"You can use \"git bisect %s\" and \"git bisect %s\" for that."
+msgstr ""
+"Вам потрібно почати з \"git bisect start\".\n"
+"Потім вам потрібно надати принаймні одну %s і %s ревізію.\n"
+"Для цього ви можете скористатися командами \"git bisect %s\" і \"git bisect "
+"%s\"."
+
+#, c-format
+msgid "bisecting only with a %s commit"
+msgstr "бісекція лише з %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 "Ви впевнені [Y/n]? "
+
+msgid "status: waiting for both good and bad commits\n"
+msgstr "статус: чекаємо на добрий і поганий коміти\n"
+
+#, c-format
+msgid "status: waiting for bad commit, %d good commit known\n"
+msgid_plural "status: waiting for bad commit, %d good commits known\n"
+msgstr[0] "статус: чекаємо на поганий коміт, відомий %d добрий коміт\n"
+msgstr[1] "статус: чекаємо на поганий коміт, відомі %d добрих коміти\n"
+msgstr[2] "статус: чекаємо на поганий коміт, відомі %d добрих комітів\n"
+
+msgid "status: waiting for good commit(s), bad commit known\n"
+msgstr "статус: чекаємо на добрий коміт(и), поганий коміт відомий\n"
+
+msgid "no terms defined"
+msgstr "терміни не визначені"
+
+#, c-format
+msgid ""
+"Your current terms are %s for the old state\n"
+"and %s for the new state.\n"
+msgstr ""
+"Ваші поточні терміни: %s для старого стану\n"
+"і %s для нового стану.\n"
+
+#, c-format
+msgid ""
+"invalid argument %s for 'git bisect terms'.\n"
+"Supported options are: --term-good|--term-old and --term-bad|--term-new."
+msgstr ""
+"неприпустимий аргумент %s для \"git bisect terms\".\n"
+"Підтримувані опції: --term-good|--term-old і --term-bad|--term-new."
+
+msgid "revision walk setup failed\n"
+msgstr "не вдалося налаштувати проходження по ревізіям\n"
+
+#, c-format
+msgid "could not open '%s' for appending"
+msgstr "не вдалося відкрити \"%s\" для додавання"
+
+msgid "'' is not a valid term"
+msgstr "\"\" не є допустимим терміном"
+
+#, c-format
+msgid "unrecognized option: '%s'"
+msgstr "нерозпізнана опція: \"%s\""
+
+#, c-format
+msgid "'%s' does not appear to be a valid revision"
+msgstr "\"%s\" не є дійсною ревізією"
+
+msgid "bad HEAD - I need a HEAD"
+msgstr "невірний HEAD - потрібен HEAD"
+
+#, c-format
+msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
+msgstr ""
+"переключення на \"%s\" завершилося невдало. Спробуйте \"git bisect start "
+"<дійсна-гілка>\"."
+
+msgid "bad HEAD - strange symbolic ref"
+msgstr "невірний HEAD - дивне символьне посилання"
+
+#, c-format
+msgid "invalid ref: '%s'"
+msgstr "неприпустиме посилання: \"%s\""
+
+msgid "You need to start by \"git bisect start\"\n"
+msgstr "Вам потрібно почати з \"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 "Ви хочете, щоб я зробив це для вас [Y/n]? "
+
+msgid "Please call `--bisect-state` with at least one argument"
+msgstr ""
+"Будь ласка, використовуйте \"--bisect-state\" з принаймні одним аргументом"
+
+#, c-format
+msgid "'git bisect %s' can take only one argument."
+msgstr "\"git bisect %s\" приймає лише один аргумент."
+
+#, c-format
+msgid "Bad rev input: %s"
+msgstr "Невірне значення ревізії: %s"
+
+#, c-format
+msgid "Bad rev input (not a commit): %s"
+msgstr "Невірне значення ревізії (не є комітом): %s"
+
+msgid "We are not bisecting."
+msgstr "Наразі ви не робите бісекцію."
+
+#, c-format
+msgid "'%s'?? what are you talking about?"
+msgstr "\"%s\"? Що ви маєте на увазі?"
+
+#, c-format
+msgid "cannot read file '%s' for replaying"
+msgstr "не вдалося прочитати файл \"%s\" для відтворення"
+
+#, c-format
+msgid "running %s\n"
+msgstr "виконання %s\n"
+
+msgid "bisect run failed: no command provided."
+msgstr "бісекція завершилася невдало: не надано команду."
+
+#, c-format
+msgid "unable to verify %s on good revision"
+msgstr "не вдалося розпізнати %s як припустиму ревізію"
+
+#, c-format
+msgid "bogus exit code %d for good revision"
+msgstr "хибний код виходу %d для доброї ревізії"
+
+#, c-format
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "бісекція завершилася невдало: код виходу %d з %s є < 0 або >= 128"
+
+#, c-format
+msgid "cannot open file '%s' for writing"
+msgstr "не вдалося відкрити файл \"%s\" для запису"
+
+msgid "bisect run cannot continue any more"
+msgstr "неможливо продовжити бісекцію"
+
+msgid "bisect run success"
+msgstr "бісекцію завершено успішно"
+
+msgid "bisect found first bad commit"
+msgstr "бісекція знайшла перший поганий коміт"
+
+#, c-format
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr ""
+"бісекція завершилася невдало: \"git bisect %s\" завершено з кодом помилки %d"
+
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "\"%s\" потребує або відсутності аргументу, або коміт"
+
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "\"%s\" потребує 0 або 1 аргумент"
+
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "\"%s\" потребує 0 аргументів"
+
+msgid "no logfile given"
+msgstr "не надано файл журналу"
+
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "\"%s\" завершено невдало: не надано команду."
+
+msgid "need a command"
+msgstr "потрібна команда"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "невідома команда: \"%s\""
+
+msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
+msgstr "git blame [<опції>] [<rev-опції>] [<ревізія>] [--] <файл>"
+
+msgid "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
+msgstr "git annotate [<опції>] [<rev-опції>] [<ревізія>] [--] <файл>"
+
+msgid "<rev-opts> are documented in git-rev-list(1)"
+msgstr "<rev-опції> задокументовані у git-rev-list(1)"
+
+#, c-format
+msgid "expecting a color: %s"
+msgstr "очікування кольору: %s"
+
+msgid "must end with a color"
+msgstr "повинно закінчуватися кольором"
+
+#, c-format
+msgid "cannot find revision %s to ignore"
+msgstr "неможливо знайти ревізію %s для ігнорування"
+
+msgid "show blame entries as we find them, incrementally"
+msgstr "показувати blame записи по мірі того, як ми їх знаходимо, поступово"
+
+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)"
+
+msgid "show work cost statistics"
+msgstr "показати статистику вартості робіт"
+
+msgid "force progress reporting"
+msgstr "примусово звітувати про хід виконання"
+
+msgid "show output score for blame entries"
+msgstr "показати вихідний показник для blame записів"
+
+msgid "show original filename (Default: auto)"
+msgstr "показати оригінальне ім’я файлу (за замовчуванням: auto)"
+
+msgid "show original linenumber (Default: off)"
+msgstr "показувати початковий номер рядка (за замовчуванням: off)"
+
+msgid "show in a format designed for machine consumption"
+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 "показувати необроблену мітку часу (за замовчуванням: off)"
+
+msgid "show long commit SHA1 (Default: off)"
+msgstr "показувати довгу версію SHA1 коміту (за замовчуванням: off)"
+
+msgid "suppress author name and timestamp (Default: off)"
+msgstr "приховати ім’я автора та мітку часу (за замовчуванням: off)"
+
+msgid "show author email instead of name (Default: off)"
+msgstr "показувати email автора замість імені (за замовчуванням: off)"
+
+msgid "ignore whitespace differences"
+msgstr "ігнорувати різницю між пробільними символами"
+
+msgid "rev"
+msgstr "ревізія"
+
+msgid "ignore <rev> when blaming"
+msgstr "ігнорувати <ревізію> при blame"
+
+msgid "ignore revisions from <file>"
+msgstr "ігнорувати ревізії з <файлу>"
+
+msgid "color redundant metadata from previous line differently"
+msgstr "розфарбувати надлишкові метадані з попереднього рядка інакше"
+
+msgid "color lines by age"
+msgstr "розфарбувати рядки за віком"
+
+msgid "spend extra cycles to find better match"
+msgstr "витрачати додаткові цикли для пошуку кращого варіанта"
+
+msgid "use revisions from <file> instead of calling git-rev-list"
+msgstr "використовувати ревізії з <файлу> замість виклику git-rev-list"
+
+msgid "use <file>'s contents as the final image"
+msgstr "використовувати вміст <файлу> як кінцевий образ"
+
+msgid "score"
+msgstr "показник"
+
+msgid "find line copies within and across files"
+msgstr "знаходити копії рядків у файлах та між ними"
+
+msgid "find line movements within and across files"
+msgstr "знаходити переміщення рядків у файлі та між ними"
+
+msgid "range"
+msgstr "діапазон"
+
+msgid "process only line range <start>,<end> or function :<funcname>"
+msgstr ""
+"обробити тільки діапазон рядків <початок>,<кінець> або функцію :<назва-"
+"функції>"
+
+msgid "--progress can't be used with --incremental or porcelain formats"
+msgstr ""
+"--progress не можна використовувати з форматами --incremental або porcelain"
+
+#. TRANSLATORS: This string is used to tell us the
+#. maximum display width for a relative timestamp in
+#. "git blame" output.  For C locale, "4 years, 11
+#. months ago", which takes 22 places, is the longest
+#. 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 місяців тому"
+
+#, c-format
+msgid "file %s has only %lu line"
+msgid_plural "file %s has only %lu lines"
+msgstr[0] "файл %s містить лише %lu рядок"
+msgstr[1] "файл %s містить лише %lu рядки"
+msgstr[2] "файл %s містить лише %lu рядків"
+
+msgid "Blaming lines"
+msgstr "Blaming рядки"
+
+msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
+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] [<шаблон>...]"
+
+msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..."
+msgstr "git branch [<опції>] [-r] (-d | -D) <имʼя-гілки>..."
+
+msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
+msgstr "git branch [<опції>] (-m | -M) [<стара-гілка>] <нова-гілка>"
+
+msgid "git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"
+msgstr "git branch [<опції>] (-c | -C) [<стара-гілка>] <нова-гілка>"
+
+msgid "git branch [<options>] [-r | -a] [--points-at]"
+msgstr "git branch [<опції>] [-r | -a] [--points-at]"
+
+msgid "git branch [<options>] [-r | -a] [--format]"
+msgstr "git branch [<опції>] [-r | -a] [--format]"
+
+#, c-format
+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'"
+msgstr "Не вдалося знайти об’єкт коміту для \"%s\""
+
+#, c-format
+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 "Не вдалося оновити конфігураційний файл"
+
+msgid "cannot use -a with -d"
+msgstr "не можна використовувати -a з -d"
+
+#, c-format
+msgid "Cannot delete branch '%s' checked out at '%s'"
+msgstr "Неможливо видалити гілку \"%s\" за адресою \"%s\""
+
+#, c-format
+msgid "remote-tracking branch '%s' not found."
+msgstr "віддалено відстежувана гілка \"%s\" не знайдена."
+
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"гілка \"%s\" не знайдена.\n"
+"Ви забули --remote?"
+
+#, c-format
+msgid "branch '%s' not found."
+msgstr "гілка \"%s\" не знайдена."
+
+#, c-format
+msgid "Deleted remote-tracking branch %s (was %s).\n"
+msgstr "Видалено гілку віддаленого відстеження %s (була %s).\n"
+
+#, c-format
+msgid "Deleted branch %s (was %s).\n"
+msgstr "Видалено гілку %s (була %s).\n"
+
+msgid "unable to parse format string"
+msgstr "не вдалося розібрати рядок форматування"
+
+msgid "could not resolve HEAD"
+msgstr "не вдалося розвʼязати HEAD"
+
+#, c-format
+msgid "HEAD (%s) points outside of refs/heads/"
+msgstr "HEAD (%s) пунктів за межами refs/heads/"
+
+#, c-format
+msgid "Branch %s is being rebased at %s"
+msgstr "Гілка %s перебазується на %s"
+
+#, c-format
+msgid "Branch %s is being bisected at %s"
+msgstr "Гілка %s бісектується в точці %s"
+
+#, 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 "Не вдалося перейменувати гілку"
+
+msgid "Branch copy failed"
+msgstr "Не вдалося створити копію гілки"
+
+#, c-format
+msgid "Created a copy of a misnamed branch '%s'"
+msgstr "Створено копію невірно названої гілки \"%s\""
+
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "Перейменовано невірно названу гілку \"%s\""
+
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr "Гілку перейменовано на %s, але HEAD не оновлено!"
+
+msgid "Branch is renamed, but update of config-file failed"
+msgstr "Гілку перейменовано, але не вдалося оновити конфігураційний файл"
+
+msgid "Branch is copied, but update of config-file failed"
+msgstr "Гілку скопійовано, але не вдалося оновити конфігураційний файл"
+
+#, c-format
+msgid ""
+"Please edit the description for the branch\n"
+"  %s\n"
+"Lines starting with '%c' will be stripped.\n"
+msgstr ""
+"Будь ласка, відредагуйте опис гілки\n"
+"  %s\n"
+"Рядки, що починаються з \"%c\", будуть вилучені.\n"
+
+msgid "Generic options"
+msgstr "Загальні опції"
+
+msgid "show hash and subject, give twice for upstream branch"
+msgstr ""
+"показувати хеш і тему, додайте двічі, щоб застосувати для висхідної гілки"
+
+msgid "suppress informational messages"
+msgstr "приховати інформаційні повідомлення"
+
+msgid "set branch tracking configuration"
+msgstr "налаштувати конфігурацію відстежуваних гілок"
+
+msgid "do not use"
+msgstr "не використовувати"
+
+msgid "upstream"
+msgstr "першоджерельне сховище"
+
+msgid "change the upstream info"
+msgstr "змінити інформацію щодо першоджерельного сховища"
+
+msgid "unset the upstream info"
+msgstr "скинути інформацію щодо першоджерельного сховища"
+
+msgid "use colored output"
+msgstr "використовувати кольоровий вивід"
+
+msgid "act on remote-tracking branches"
+msgstr "працювати з віддалено відстежуваними гілками"
+
+msgid "print only branches that contain the commit"
+msgstr "виводити тільки гілки, що містять цей коміт"
+
+msgid "print only branches that don't contain the commit"
+msgstr "виводити тільки гілки, що не містять цей коміт"
+
+msgid "Specific git-branch actions:"
+msgstr "Специфічні git-branch дії:"
+
+msgid "list both remote-tracking and local branches"
+msgstr "показати як віддалено відстежувані, так і локальні гілки"
+
+msgid "delete fully merged branch"
+msgstr "видалити повністю злиту гілку"
+
+msgid "delete branch (even if not merged)"
+msgstr "видалити гілку (навіть не повністю злиту)"
+
+msgid "move/rename a branch and its reflog"
+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 "скопіювати гілку та її журнал посилань"
+
+msgid "copy a branch, even if target exists"
+msgstr "скопіювати гілку, навіть якщо призначення існує"
+
+msgid "list branch names"
+msgstr "показати назви гілок"
+
+msgid "show current branch name"
+msgstr "показати назву поточної гілки"
+
+msgid "create the branch's reflog"
+msgstr "створити журнал посилань гілки"
+
+msgid "edit the description for the branch"
+msgstr "редагувати опис гілки"
+
+msgid "force creation, move/rename, deletion"
+msgstr "примусове створення, переміщення/перейменування, видалення"
+
+msgid "print only branches that are merged"
+msgstr "вивести тільки злиті гілки"
+
+msgid "print only branches that are not merged"
+msgstr "вивести тільки не злиті гілки"
+
+msgid "list branches in columns"
+msgstr "виводити гілки в стовпчиках"
+
+msgid "object"
+msgstr "обʼєкт"
+
+msgid "print only branches of the object"
+msgstr "виводити тільки гілки об’єкта"
+
+msgid "sorting and filtering are case insensitive"
+msgstr "сортувати та фільтрувати незалежно від регістру"
+
+msgid "recurse through submodules"
+msgstr "рекурсивно через підмодулі"
+
+msgid "format to use for the output"
+msgstr "формат, що використовувати для виводу"
+
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Не вдалося розпізнати HEAD як дійсне посилання."
+
+msgid "HEAD not found below refs/heads!"
+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 "--recurse-submodules можна використовувати лише для створення гілок"
+
+msgid "branch name required"
+msgstr "назва гілки є обовʼязковою"
+
+msgid "Cannot give description to detached HEAD"
+msgstr "Неможливо встановити опис відокремленому HEAD"
+
+msgid "cannot edit description of more than one branch"
+msgstr "неможливо редагувати опис більш ніж однієї гілки"
+
+msgid "cannot copy the current branch while not on any."
+msgstr "неможливо скопіювати поточну гілку, не перебуваючи на жодній з них."
+
+msgid "cannot rename the current branch while not on any."
+msgstr "неможливо перейменувати поточну гілку, не перебуваючи на жодній з них."
+
+msgid "too many branches for a copy operation"
+msgstr "забагато гілок для операції копіювання"
+
+msgid "too many arguments for a rename operation"
+msgstr "забагато аргументів для операції перейменування"
+
+msgid "too many arguments to set new upstream"
+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'"
+msgstr "немає такої гілки \"%s\""
+
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr "гілка \"%s\" не існує"
+
+msgid "too many arguments to unset upstream"
+msgstr "забагато аргументів для скидання значення першоджерельного сховища"
+
+msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgstr ""
+"неможливво скинути значення першоджерельного сховища для HEAD, який не "
+"вказує на жодну гілку."
+
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr "Гілка \"%s\" не має інформації щодо першоджерельного сховища"
+
+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 "версія git:\n"
+
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() завершився невдало з помилкою \"%s\" (%d)\n"
+
+msgid "compiler info: "
+msgstr "інформація щодо компілятора: "
+
+msgid "libc info: "
+msgstr "информація щодо libc: "
+
+msgid "not run from a git repository - no hooks to show\n"
+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"
+"Please answer the following questions to help us understand your issue.\n"
+"\n"
+"What did you do before the bug happened? (Steps to reproduce your issue)\n"
+"\n"
+"What did you expect to happen? (Expected behavior)\n"
+"\n"
+"What happened instead? (Actual behavior)\n"
+"\n"
+"What's different between what you expected and what actually happened?\n"
+"\n"
+"Anything else you want to add:\n"
+"\n"
+"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 "режим"
+
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"створити додатковий zip-архів з детальною діагностикою (за замовчуванням "
+"\"stats\")"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "вказати місце призначення для файла(-ів) звіта про помилку"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "вказати суфікс формату strftime для назви файла(-ів)"
+
+#, c-format
+msgid "could not create leading directories for '%s'"
+msgstr "не вдалося створити провідні каталоги для \"%s\""
+
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "не вдалося створити архів діагностики %s"
+
+msgid "System Info"
+msgstr "Інформація про систему"
+
+msgid "Enabled Hooks"
+msgstr "Увімкнені гачки"
+
+#, c-format
+msgid "unable to write to %s"
+msgstr "не вдалося записати до %s"
+
+#, c-format
+msgid "Created new report at '%s'.\n"
+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 "git bundle verify [-q | --quiet] <файл>"
+
+msgid "git bundle list-heads <file> [<refname>...]"
+msgstr "git bundle list-heads <файл> [<назва-посилання>...]"
+
+msgid "git bundle unbundle [--progress] <file> [<refname>...]"
+msgstr "git bundle unbundle [--progress] <файл> [<назва-посилання>...]"
+
+msgid "need a <file> argument"
+msgstr "потрібен аргумент <файл>"
+
+msgid "do not show progress meter"
+msgstr "не показувати хід виконання"
+
+msgid "show progress meter"
+msgstr "показувати хід виконання"
+
+msgid "historical; same as --progress"
+msgstr "історичний; те саме, що --progress"
+
+msgid "historical; does nothing"
+msgstr "історична; не робить нічогісенько"
+
+msgid "specify bundle format version"
+msgstr "вказати версію формату пакунка"
+
+msgid "Need a repository to create a bundle."
+msgstr "Для створення пакунка потрібне сховище."
+
+msgid "do not show bundle details"
+msgstr "не показувати деталі пакунка"
+
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s у порядку\n"
+
+msgid "Need a repository to unbundle."
+msgstr "Потрібне сховище для розділення."
+
+msgid "Unbundling objects"
+msgstr "Розділення об’єктів"
+
+#, c-format
+msgid "cannot read object %s '%s'"
+msgstr "неможливо прочитати об’єкт %s \"%s\""
+
+msgid "flush is only for --buffer mode"
+msgstr "flush тільки для режиму --buffer"
+
+msgid "empty command in input"
+msgstr "порожня команда на вході"
+
+#, c-format
+msgid "whitespace before command: '%s'"
+msgstr "пробільний символ перед командою: \"%s\""
+
+#, c-format
+msgid "%s requires arguments"
+msgstr "%s потребує аргументів"
+
+#, c-format
+msgid "%s takes no arguments"
+msgstr "%s не потребує аргументів"
+
+msgid "only one batch option may be specified"
+msgstr "можна вказати лише одну групову опцію"
+
+msgid "git cat-file <type> <object>"
+msgstr "git cat-file <тип> <об’єкт>"
+
+msgid "git cat-file (-e | -p) <object>"
+msgstr "git cat-file (-e | -p) <об’єкт>"
+
+msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
+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]"
+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 "Перевірити існування об’єкта або видати вміст об’єкта"
+
+msgid "check if <object> exists"
+msgstr "перевірити, чи існує <об’єкт>"
+
+msgid "pretty-print <object> content"
+msgstr "pretty-print вміст <об’єкта>"
+
+msgid "Emit [broken] object attributes"
+msgstr "Видати [пошкоджені] атрибути об’єкта"
+
+msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
+msgstr ""
+"показати тип об’єкта (один з \"blob\", \"tree\", \"commit\", \"tag\", ...)"
+
+msgid "show object size"
+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 "Пакетний запит об’єктів з stdin (або --batch-all-objects)"
+
+msgid "show full <object> or <rev> contents"
+msgstr "показати повний вміст <об’єкта> або <ревізії>"
+
+msgid "like --batch, but don't emit <contents>"
+msgstr "як --batch, але не виводить <вміст>"
+
+msgid "stdin is NUL-terminated"
+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 "з --batch[-check]: ігнорує stdin, групує всі відомі об’єкти"
+
+msgid "Change or optimize batch output"
+msgstr "Змінити або оптимізувати груповий вивід"
+
+msgid "buffer --batch output"
+msgstr "буферизувати --batch вивід"
+
+msgid "follow in-tree symlinks"
+msgstr "розвʼязувати символьні посилання в дереві"
+
+msgid "do not order objects before emitting them"
+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 "виконати textconv над вмістом об’єкта"
+
+msgid "run filters on object's content"
+msgstr "запустити фільтри на вміст об’єкта"
+
+msgid "blob|tree"
+msgstr "blob|дерево"
+
+msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
+msgstr "використати <шлях> для (--textconv | --filters); не з \"batch\""
+
+#, c-format
+msgid "'%s=<%s>' needs '%s' or '%s'"
+msgstr "\"%s=<%s>\" потребує \"%s\" або \"%s\""
+
+msgid "path|tree-ish"
+msgstr "шлях|деревоподібне-джерело"
+
+#, c-format
+msgid "'%s' requires a batch mode"
+msgstr "\"%s\" потребує групового режиму"
+
+#, c-format
+msgid "'-%c' is incompatible with batch mode"
+msgstr "\"-%c\" несумісний з груповим режимом"
+
+msgid "batch modes take no arguments"
+msgstr "групові режими не потребують аргументів"
+
+#, c-format
+msgid "<rev> required with '%s'"
+msgstr "<ревізія> є обов’язковою для \"%s\""
+
+#, c-format
+msgid "<object> required with '-%c'"
+msgstr "<об’єкт> є обов’язковим для \"-%c\""
+
+#, c-format
+msgid "only two arguments allowed in <type> <object> mode, not %d"
+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 | "
+"<атрибут>...]"
+
+msgid "report all attributes set on file"
+msgstr "звітувати про всі атрибути, встановлені у файлі"
+
+msgid "use .gitattributes only from the index"
+msgstr "використовувати .gitattributes тільки з індексу"
+
+msgid "read file names from stdin"
+msgstr "зчитувати назви файлів з stdin"
+
+msgid "terminate input and output records by a NUL character"
+msgstr "завершувати вхідні та вихідні записи символом NUL"
+
+msgid "<tree-ish>"
+msgstr "<деревоподібне-джерело>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "атрибути якого деревоподібного джерела перевіряти"
+
+msgid "suppress progress reporting"
+msgstr "не звітувати про хід виконання"
+
+msgid "show non-matching input paths"
+msgstr "показати неспівпадіння вхідних шляхів"
+
+msgid "ignore index when checking"
+msgstr "ігнорувати індекс під час перевірки"
+
+msgid "cannot specify pathnames with --stdin"
+msgstr "неможливо вказувати назви шляхів із --stdin"
+
+msgid "-z only makes sense with --stdin"
+msgstr "-z має сенс тільки з --stdin"
+
+msgid "no path specified"
+msgstr "шлях не зазначено"
+
+msgid "--quiet is only valid with a single pathname"
+msgstr "--quiet дійсний лише з однією назвою шляху"
+
+msgid "cannot have both --quiet and --verbose"
+msgstr "неможливо мати одночасно --quiet і --verbose"
+
+msgid "--non-matching is only valid with --verbose"
+msgstr "--non-matching діє тільки з --verbose"
+
+msgid "git check-mailmap [<options>] <contact>..."
+msgstr "git check-mailmap [<опції>] <контакт>..."
+
+msgid "also read contacts from stdin"
+msgstr "також читати контакти з stdin"
+
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr "не вдалося розібрати контакт: %s"
+
+msgid "no contacts specified"
+msgstr "контакти не вказані"
+
+msgid "git checkout--worker [<options>]"
+msgstr "git checkout--worker [<опції>]"
+
+msgid "string"
+msgstr "строка"
+
+msgid "when creating files, prepend <string>"
+msgstr "при створенні файлів додавати <строку> напочатку"
+
+msgid "git checkout-index [<options>] [--] [<file>...]"
+msgstr "git checkout-index [<опції>] [—] [<файл>...]"
+
+msgid "stage should be between 1 and 3 or all"
+msgstr "стадія має бути від 1 до 3 або all"
+
+msgid "check out all files in the index"
+msgstr "переключити стан для всіх файлів в індексі"
+
+msgid "do not skip files with skip-worktree set"
+msgstr "не пропускати файли зі встановленим skip-worktree"
+
+msgid "force overwrite of existing files"
+msgstr "примусово перезаписати існуючі файли"
+
+msgid "no warning for existing files and files not in index"
+msgstr "не попереджувати про існуючі файли та файли, яких немає в індексі"
+
+msgid "don't checkout new files"
+msgstr "не переключати стан для нових файлів"
+
+msgid "update stat information in the index file"
+msgstr "оновити статистичну інформацію в індексному файлі"
+
+msgid "read list of paths from the standard input"
+msgstr "зчитати список шляхів зі стандартного вводу"
+
+msgid "write the content to temporary files"
+msgstr "записати вміст у тимчасові файли"
+
+msgid "copy out the files from named stage"
+msgstr "скопіювати файли з іменованої стадії"
+
+msgid "git checkout [<options>] <branch>"
+msgstr "git checkout [<опції>] <гілка>"
+
+msgid "git checkout [<options>] [<branch>] -- <file>..."
+msgstr "git checkout [<опції>] [<гілка>] -- <файл>..."
+
+msgid "git switch [<options>] [<branch>]"
+msgstr "git switch [<опції>] [<гілка>]"
+
+msgid "git restore [<options>] [--source=<branch>] <file>..."
+msgstr "git restore [<опції>] [--source=<гілка>] <файл>..."
+
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr "шлях \"%s\" не містить нашої версії"
+
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "шлях \"%s\" не містить їхньої версії"
+
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr "шлях \"%s\" не містить всіх необхідних версій"
+
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr "шлях \"%s\" не містить необхідних версій"
+
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "шлях \"%s\": неможливо злити"
+
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "Неможливо додати результат злиття для \"%s\""
+
+#, c-format
+msgid "Recreated %d merge conflict"
+msgid_plural "Recreated %d merge conflicts"
+msgstr[0] "Відтворено %d конфлікт злиття"
+msgstr[1] "Відтворено %d конфлікта злиття"
+msgstr[2] "Відтворено %d конфліктів злиття"
+
+#, c-format
+msgid "Updated %d path from %s"
+msgid_plural "Updated %d paths from %s"
+msgstr[0] "Оновлено %d шлях з %s"
+msgstr[1] "Оновлено %d шляхи з %s"
+msgstr[2] "Оновлено %d шляхів з %s"
+
+#, c-format
+msgid "Updated %d path from the index"
+msgid_plural "Updated %d paths from the index"
+msgstr[0] "Оновлено %d шлях з індексу"
+msgstr[1] "Оновлено %d шляхи з індексу"
+msgstr[2] "Оновлено %d шляхів з індексу"
+
+#, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr "\"%s\" не можна використовувати зі шляхами оновлення"
+
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr "Неможливо одночасно оновити шляхи та переключитись на гілку \"%s\"."
+
+#, c-format
+msgid "neither '%s' or '%s' is specified"
+msgstr "не вказано ні \"%s\", ні \"%s\""
+
+#, c-format
+msgid "'%s' must be used when '%s' is not specified"
+msgstr "\"%s\" повинен використовуватися, якщо не вказано \"%s\""
+
+#, c-format
+msgid "'%s' or '%s' cannot be used with %s"
+msgstr "\"%s\" або \"%s\" не можна використовувати з %s"
+
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr "шлях '%s' не злитий"
+
+msgid "you need to resolve your current index first"
+msgstr "спочатку потрібно розібратись з вашим поточним індексом"
+
+#, c-format
+msgid ""
+"cannot continue with staged changes in the following files:\n"
+"%s"
+msgstr ""
+"неможливо продовжити з індексованими змінами в наступних файлах:\n"
+"%s"
+
+#, c-format
+msgid "Can not do reflog for '%s': %s\n"
+msgstr "Неможливо виконати reflog для \"%s\": %s\n"
+
+msgid "HEAD is now at"
+msgstr "HEAD зараз на"
+
+msgid "unable to update HEAD"
+msgstr "не вдалося оновити HEAD"
+
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "Скинути гілку \"%s\"\n"
+
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "Вже на \"%s\"\n"
+
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr "Переключено на та скинуто гілку '%s'\n"
+
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "Переключено на нову гілку \"%s\"\n"
+
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "Переключено на гілку \"%s\"\n"
+
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... та ще %d.\n"
+
+#, c-format
+msgid ""
+"Warning: you are leaving %d commit behind, not connected to\n"
+"any of your branches:\n"
+"\n"
+"%s\n"
+msgid_plural ""
+"Warning: you are leaving %d commits behind, not connected to\n"
+"any of your branches:\n"
+"\n"
+"%s\n"
+msgstr[0] ""
+"Попередження: ви залишаєте позаду %d коміт, не підключений до\n"
+"жодної з ваших гілок:\n"
+"\n"
+"%s\n"
+msgstr[1] ""
+"Попередження: ви залишаєте позаду %d коміти, не підключених до\n"
+"жодної з ваших гілок:\n"
+"\n"
+"%s\n"
+msgstr[2] ""
+"Попередження: ви залишаєте позаду %d комітів, не підключених до\n"
+"жодної з ваших гілок:\n"
+"\n"
+"%s\n"
+
+#, c-format
+msgid ""
+"If you want to keep it by creating a new branch, this may be a good time\n"
+"to do so with:\n"
+"\n"
+" git branch <new-branch-name> %s\n"
+"\n"
+msgid_plural ""
+"If you want to keep them by creating a new branch, this may be a good time\n"
+"to do so with:\n"
+"\n"
+" git branch <new-branch-name> %s\n"
+"\n"
+msgstr[0] ""
+"Якщо ви хочете зберегти його, створивши нову гілку, то зараз є чудова "
+"нагода\n"
+"зробити це за допомогою:\n"
+"git branch <назва-нової-гілки> %s\n"
+"\n"
+msgstr[1] ""
+"Якщо ви хочете зберегти їх, створивши нову гілку, то зараз є чудова нагода\n"
+"зробити це за допомогою:\n"
+"git branch <назва-нової-гілки> %s\n"
+"\n"
+msgstr[2] ""
+"Якщо ви хочете зберегти їх, створивши нову гілку, то зараз є чудова нагода\n"
+"зробити це за допомогою:\n"
+"git branch <назва-нової-гілки> %s\n"
+"\n"
+
+msgid "internal error in revision walk"
+msgstr "внутрішня помилка при проходженні по ревізіям"
+
+msgid "Previous HEAD position was"
+msgstr "Попередня позиція HEAD була"
+
+msgid "You are on a branch yet to be born"
+msgstr "Ви на гілці, яка ще не iснує"
+
+#, c-format
+msgid ""
+"'%s' could be both a local file and a tracking branch.\n"
+"Please use -- (and optionally --no-guess) to disambiguate"
+msgstr ""
+"\"%s\" може бути як локальним файлом, так і відстежуваною гілкою.\n"
+"Будь ласка, використовуйте -- (і, за бажанням, --no-guess), для визначення"
+
+msgid ""
+"If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
+"you can do so by fully qualifying the name with the --track option:\n"
+"\n"
+"    git checkout --track origin/<name>\n"
+"\n"
+"If you'd like to always have checkouts of an ambiguous <name> prefer\n"
+"one remote, e.g. the 'origin' remote, consider setting\n"
+"checkout.defaultRemote=origin in your config."
+msgstr ""
+"Якщо ви хотіли переключитись на віддалено відстежувану гілку, наприклад, "
+"'origin',\n"
+"ви можете зробити це, повністю вказавши назву з опцією --track:\n"
+"\n"
+"    git checkout --track origin/<назва>.\n"
+"\n"
+"Якщо при переключенні з неоднозначною <назвою> ви бажаєте завжди віддавати "
+"перевагу\n"
+"певному віддаленому сховищу, наприклад, 'origin', розгляньте можливість "
+"додання\n"
+"checkout.defaultRemote=origin до вашого конфігураційного файлу."
+
+#, c-format
+msgid "'%s' matched multiple (%d) remote tracking branches"
+msgstr "\"%s\" відповідає кільком (%d) гілкам віддаленого відстежування"
+
+msgid "only one reference expected"
+msgstr "очікувалось тільки одне посилання"
+
+#, c-format
+msgid "only one reference expected, %d given."
+msgstr "очікувалось тільки одне посилання, надано %d."
+
+#, c-format
+msgid "invalid reference: %s"
+msgstr "неприпустиме посилання: %s"
+
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr "посилання не є деревом: %s"
+
+#, c-format
+msgid "a branch is expected, got tag '%s'"
+msgstr "очікувалась гілка, надано тег \"%s\""
+
+#, c-format
+msgid "a branch is expected, got remote branch '%s'"
+msgstr "очікувалась гілка, надана віддалена гілка \"%s\""
+
+#, c-format
+msgid "a branch is expected, got '%s'"
+msgstr "очікувалась гілка, надано \"%s\""
+
+#, c-format
+msgid "a branch is expected, got commit '%s'"
+msgstr "очікувалась гілка, надано коміт \"%s\""
+
+msgid ""
+"If you want to detach HEAD at the commit, try again with the --detach option."
+msgstr ""
+"Якщо ви хочете від'єднати HEAD на цьому коміті, спробуйте ще раз з опцією --"
+"detach."
+
+msgid ""
+"cannot switch branch while merging\n"
+"Consider \"git merge --quit\" or \"git worktree add\"."
+msgstr ""
+"неможливо змінити гілку під час злиття\n"
+"Спробуйте \"git merge --quit\" або \"git worktree add\"."
+
+msgid ""
+"cannot switch branch in the middle of an am session\n"
+"Consider \"git am --quit\" or \"git worktree add\"."
+msgstr ""
+"неможливо змінити гілку під час am сеансу\n"
+"Спробуйте \"git am --quit\" або \"git worktree add\"."
+
+msgid ""
+"cannot switch branch while rebasing\n"
+"Consider \"git rebase --quit\" or \"git worktree add\"."
+msgstr ""
+"неможливо змінити гілку під час перебазування\n"
+"Спробуйте \"git rebase --quit\" або \"git worktree add\"."
+
+msgid ""
+"cannot switch branch while cherry-picking\n"
+"Consider \"git cherry-pick --quit\" or \"git worktree add\"."
+msgstr ""
+"неможливо змінити гілку під час висмикування\n"
+"Спробуйте \"git cherry-pick --quit\" або \"git worktree add\"."
+
+msgid ""
+"cannot switch branch while reverting\n"
+"Consider \"git revert --quit\" or \"git worktree add\"."
+msgstr ""
+"неможливо змінити гілку під час вивертання\n"
+"Спробуйте \"git revert --quit\" або \"git worktree add\"."
+
+msgid "you are switching branch while bisecting"
+msgstr "ви переключаєте гілку під час бісекції"
+
+msgid "paths cannot be used with switching branches"
+msgstr "шляхи не можуть використовуватись при переключенні гілок"
+
+#, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "'%s' не може використовуватись при переключенні гілок"
+
+#, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "'%s' не може використовуватись з '%s'"
+
+#, c-format
+msgid "'%s' cannot take <start-point>"
+msgstr "'%s' не може прийняти <стартова-точка>"
+
+#, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "Неможливо переключити гілку на не коміт '%s'"
+
+msgid "missing branch or commit argument"
+msgstr "відсутня гілка або коміт"
+
+msgid "perform a 3-way merge with the new branch"
+msgstr "здійснити 3-стороннє злиття з новою гілкою"
+
+msgid "style"
+msgstr "стиль"
+
+msgid "conflict style (merge, diff3, or zdiff3)"
+msgstr "конфлікт стилю (merge, diff3 або zdiff3)"
+
+msgid "detach HEAD at named commit"
+msgstr "відʼєднати HEAD на вказаному коміті"
+
+msgid "force checkout (throw away local modifications)"
+msgstr "переключити примусово (викинути локальні зміни)"
+
+msgid "new-branch"
+msgstr "нова-гілка"
+
+msgid "new unparented branch"
+msgstr "нова гілка без джерела"
+
+msgid "update ignored files (default)"
+msgstr "оновити ігноровані файли (за замовчуванням)"
+
+msgid "do not check if another worktree is holding the given ref"
+msgstr "не перевіряти, чи інше робоче дерево містить дане посилання"
+
+msgid "checkout our version for unmerged files"
+msgstr "використовувати нашу версію для не злитих файлів"
+
+msgid "checkout their version for unmerged files"
+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\" не можна використовувати разом"
+
+msgid "--track needs a branch name"
+msgstr "--track потребує назви гілки"
+
+#, c-format
+msgid "missing branch name; try -%c"
+msgstr "відсутня назва гілки; спробуйте -%c"
+
+#, c-format
+msgid "could not resolve %s"
+msgstr "не вдалося розвʼязати %s"
+
+msgid "invalid path specification"
+msgstr "неприпустиме зазначення шляху"
+
+#, c-format
+msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
+msgstr "'%s' не є комітом, і з нього не можна створити гілку '%s'"
+
+#, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
+msgstr "git checkout: --detach не приймає аргумент шляху '%s'"
+
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+"git checkout: --ours/--theirs, --force та --merge несумісні при\n"
+"при прееключенні індексу."
+
+msgid "you must specify path(s) to restore"
+msgstr "необхідно вказати шлях(и) для відновлення"
+
+msgid "branch"
+msgstr "гілка"
+
+msgid "create and checkout a new branch"
+msgstr "створити та перейти до нової гілки"
+
+msgid "create/reset and checkout a branch"
+msgstr "створити/скинути та перейти до нової гілки"
+
+msgid "create reflog for new branch"
+msgstr "створити журнал посилань для нової гілки"
+
+msgid "second guess 'git checkout <no-such-branch>' (default)"
+msgstr "друга здогадка \"git checkout <гілка-не-існує>\" (за замовчуванням)"
+
+msgid "use overlay mode (default)"
+msgstr "використовувати режим накладення (за замовчуванням)"
+
+msgid "create and switch to a new branch"
+msgstr "створити та переключити на нову гілку"
+
+msgid "create/reset and switch to a branch"
+msgstr "створити/скинути та переключити на гілку"
+
+msgid "second guess 'git switch <no-such-branch>'"
+msgstr "друга здогадка \"git switch <гілка-не-існує>\" (за замовчуванням)"
+
+msgid "throw away local modifications"
+msgstr "викинути локальні зміни"
+
+msgid "which tree-ish to checkout from"
+msgstr "з якого деревоподібного джерела створювати"
+
+msgid "restore the index"
+msgstr "відновити індекс"
+
+msgid "restore the working tree (default)"
+msgstr "відновити робоче дерево (за замовчуванням)"
+
+msgid "ignore unmerged entries"
+msgstr "ігнорувати не злиті записи"
+
+msgid "use overlay mode"
+msgstr "використовувати режим накладення"
+
+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"
+msgstr "Видалення %s\n"
+
+#, c-format
+msgid "Would remove %s\n"
+msgstr "Було б видалено %s\n"
+
+#, c-format
+msgid "Skipping repository %s\n"
+msgstr "Пропуск сховища %s\n"
+
+#, c-format
+msgid "Would skip repository %s\n"
+msgstr "Було б пропущено сховище %s\n"
+
+#, c-format
+msgid "failed to remove %s"
+msgstr "не вдалося видалити %s"
+
+#, c-format
+msgid "could not lstat %s\n"
+msgstr "не вдалося виконати lstat %s\n"
+
+msgid "Refusing to remove current working directory\n"
+msgstr "Відмовлено у видаленні поточної робочої директорії\n"
+
+msgid "Would refuse to remove current working directory\n"
+msgstr "Було б відмовлено у видаленні поточної робочої директорії\n"
+
+#, c-format
+msgid ""
+"Prompt help:\n"
+"1          - select a numbered item\n"
+"foo        - select item based on unique prefix\n"
+"           - (empty) select nothing\n"
+msgstr ""
+"Підказка по опціям:\n"
+"1          - вибрати пронумерований елемент\n"
+"foo        - вибрати елемент за унікальним префіксом\n"
+"           - (порожньо) - не вибирати нічого\n"
+
+#, c-format
+msgid ""
+"Prompt help:\n"
+"1          - select a single item\n"
+"3-5        - select a range of items\n"
+"2-3,6-9    - select multiple ranges\n"
+"foo        - select item based on unique prefix\n"
+"-...       - unselect specified items\n"
+"*          - 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 "Га (%s)?\n"
+
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr "Введіть шаблони ігнорування>> "
+
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr "ПОПЕРЕДЖЕННЯ: Не вдалося знайти елементи, що відповідають: %s"
+
+msgid "Select items to delete"
+msgstr "Виберіть елементи для видалення"
+
+#. TRANSLATORS: Make sure to keep [y/N] as is
+
+#, c-format
+msgid "Remove %s [y/N]? "
+msgstr "Видалити %s [y/N]? "
+
+msgid ""
+"clean               - start cleaning\n"
+"filter by pattern   - exclude items from deletion\n"
+"select by numbers   - select items to be deleted by numbers\n"
+"ask each            - confirm each deletion (like \"rm -i\")\n"
+"quit                - stop cleaning\n"
+"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] "Видалить наступні елементи:"
+
+msgid "No more files to clean, exiting."
+msgstr "Більше немає файлів для прибирання, вихід."
+
+msgid "do not print names of files removed"
+msgstr "не виводити назви видалених файлів"
+
+msgid "force"
+msgstr "примусово"
+
+msgid "interactive cleaning"
+msgstr "інтерактивне прибирання"
+
+msgid "remove whole directories"
+msgstr "видаляти цілі директорії"
+
+msgid "pattern"
+msgstr "шаблон"
+
+msgid "add <pattern> to ignore rules"
+msgstr "додати <шаблон> в правила ігнорування"
+
+msgid "remove ignored files, too"
+msgstr "видалити також ігноровані файли"
+
+msgid "remove only ignored files"
+msgstr "видалити лише ігноровані файли"
+
+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 не можна використовувати разом"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<опції>] [--] <сховище> [<директорія>]"
+
+msgid "don't clone shallow repository"
+msgstr "не клонувати неглибоке сховище"
+
+msgid "don't create a checkout"
+msgstr "не переходити на гілку"
+
+msgid "create a bare repository"
+msgstr "створити порожнє сховище"
+
+msgid "create a mirror repository (implies bare)"
+msgstr "створити дзеркальне сховище (включає опцію bare)"
+
+msgid "to clone from a local repository"
+msgstr "клонувати з локального сховища"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "не використовувати локальні жорсткі посилання, завжди копіювати"
+
+msgid "setup as shared repository"
+msgstr "налаштувати як спільне сховище"
+
+msgid "pathspec"
+msgstr "визначник шляху"
+
+msgid "initialize submodules in the clone"
+msgstr "ініціалізувати підмодулі в клоні"
+
+msgid "number of submodules cloned in parallel"
+msgstr "кількість підмодулів, що клонуються паралельно"
+
+msgid "template-directory"
+msgstr "директорія-шаблонів"
+
+msgid "directory from which templates will be used"
+msgstr "директорія, з якої брати шаблони"
+
+msgid "reference repository"
+msgstr "посилання на сховище"
+
+msgid "use --reference only while cloning"
+msgstr "використовуйте --reference тільки під час клонування"
+
+msgid "name"
+msgstr "назва"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr ""
+"використовуйте <назва> замість \"origin\" для відстежування першоджерельного "
+"сховища"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "перейти до <гілки> замість HEAD віддаленого сховища"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "шлях до git-upload-pack на віддаленому сервері"
+
+msgid "depth"
+msgstr "глибина"
+
+msgid "create a shallow clone of that depth"
+msgstr "створити неглибокий клон вказаної глибини"
+
+msgid "create a shallow clone since a specific time"
+msgstr "створити неглибокий клон з певного часу"
+
+msgid "revision"
+msgstr "ревізія"
+
+msgid "deepen history of shallow clone, excluding rev"
+msgstr "поглибити історію неглибокого клону, за винятком ревізії"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr "клонувати лише одну гілку, HEAD або --branch"
+
+msgid "don't clone any tags, and make later fetches not to follow them"
+msgstr ""
+"не клонувати жодних тегів і не слідувати за ними під час отримувань пізніше"
+
+msgid "any cloned submodules will be shallow"
+msgstr "будь-які клоновані підмодулі будуть неглибокими"
+
+msgid "gitdir"
+msgstr "git директорія"
+
+msgid "separate git dir from working tree"
+msgstr "відокремити git-директорію від робочого дерева"
+
+msgid "key=value"
+msgstr "ключ=значення"
+
+msgid "set config inside the new repository"
+msgstr "встановити конфігурацію всередині нового сховища"
+
+msgid "server-specific"
+msgstr "тільки для сервера"
+
+msgid "option to transmit"
+msgstr "опція для передачі"
+
+msgid "apply partial clone filters to submodules"
+msgstr "застосувати фільтри часткового клонування до підмодулів"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr ""
+"будь-які клоновані підмодулі будуть використовувати свою віддалено "
+"відстежувану гілку"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr ""
+"ініціалізувати, щоб файл розрідженого переходу включав лише файли в корені"
+
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "URI для завантаження пакунків перед отриманням з віддаленого джерела"
+
+#, c-format
+msgid "info: Could not add alternate for '%s': %s\n"
+msgstr "инфо: Не вдалося додати запозичений обʼєкт для \"%s\": %s\n"
+
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "не вдалося виконати stat \"%s\""
+
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s існує і не є директорією"
+
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "\"%s\" є символьним посиланням, відмовлено в клонуванні з --local"
+
+#, c-format
+msgid "failed to start iterator over '%s'"
+msgstr "не вдалося запустити перебір для \"%s\""
+
+#, c-format
+msgid "symlink '%s' exists, refusing to clone with --local"
+msgstr "символьне посилання \"%s\" існує, не можу клонувати з --local"
+
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "не вдалося видалити \"%s\""
+
+#, c-format
+msgid "failed to create link '%s'"
+msgstr "не вдалося створити посилання \"%s\""
+
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "не вдалося скопіювати файл у \"%s\""
+
+#, c-format
+msgid "failed to iterate over '%s'"
+msgstr "не вдалося перебрати \"%s\""
+
+#, c-format
+msgid "done.\n"
+msgstr "готово.\n"
+
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry with 'git restore --source=HEAD :/'\n"
+msgstr ""
+"Клонування пройшло успішно, але не вдалося перейти на гілку.\n"
+"Ви можете перевірити, що було додано за допомогою 'git status'\n"
+"і повторити спробу за допомогою 'git restore --source=HEAD :/'\n"
+
+#, c-format
+msgid "Could not find remote branch %s to clone."
+msgstr "Не вдалося знайти віддалену гілку %s для клонування."
+
+msgid "remote did not send all necessary objects"
+msgstr "віддалене сховище не надіслало всі необхідні обʼєкти"
+
+#, c-format
+msgid "unable to update %s"
+msgstr "не вдалося оновити %s"
+
+msgid "failed to initialize sparse-checkout"
+msgstr "не вдалося ініціалізувати розріджений перехід"
+
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "віддалений HEAD посилається на неіснуючого рефа, неможливо перейти"
+
+msgid "unable to checkout working tree"
+msgstr "не вдалося завантажити стан робочої директорії"
+
+msgid "unable to write parameters to config file"
+msgstr "не вдалося записати параметри до конфігураційного файлу"
+
+msgid "cannot repack to clean up"
+msgstr "неможливо перепакувати, щоб очистити"
+
+msgid "cannot unlink temporary alternates file"
+msgstr "неможливо видалити тимчасовий файл запозичених обʼєктів"
+
+msgid "Too many arguments."
+msgstr "Забагато аргументів."
+
+msgid "You must specify a repository to clone."
+msgstr "Треба вказати сховище для клонування."
+
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri несумісний з --depth, --shallow-since та --shallow-exclude"
+
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr "сховище \"%s\" не існує"
+
+#, c-format
+msgid "depth %s is not a positive number"
+msgstr "глибина %s не є додатнім числом"
+
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr "шлях призначення \"%s\" вже існує і не є порожньою директорією."
+
+#, c-format
+msgid "repository path '%s' already exists and is not an empty directory."
+msgstr "шлях до сховища \"%s\" вже існує і не є порожньою директорією."
+
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr "робоче дерево \"%s\" вже існує."
+
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr "не вдалося створити провідні директорії для \"%s\""
+
+#, c-format
+msgid "could not create work tree dir '%s'"
+msgstr "не вдалося створити директорію робочого дерева \"%s\""
+
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "Клонування у порожнє сховище \"%s\"...\n"
+
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "Клонування в \"%s\"..\n"
+
+msgid ""
+"clone --recursive is not compatible with both --reference and --reference-if-"
+"able"
+msgstr ""
+"clone --recursive не сумісне з --reference та --reference-if-able одночасно"
+
+#, c-format
+msgid "'%s' is not a valid remote name"
+msgstr "\"%s\" не є дійсною назвою віддаленого сховища"
+
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr ""
+"--depth ігнорується у локальних клонах; використовуйте file:// замість цього."
+
+msgid "--shallow-since is ignored in local clones; use file:// instead."
+msgstr ""
+"--shallow-since ігнорується у локальних клонах; використовуйте file:// "
+"замість цього."
+
+msgid "--shallow-exclude is ignored in local clones; use file:// instead."
+msgstr ""
+"--shallow-exclude ігнорується у локальних клонах; використовуйте file:// "
+"замість цього."
+
+msgid "--filter is ignored in local clones; use file:// instead."
+msgstr ""
+"--filter ігнорується у локальних клонах; використовуйте file:// замість "
+"нього."
+
+msgid "source repository is shallow, reject to clone."
+msgstr "джерельне сховище є неглибоким, клонування відхилено."
+
+msgid "source repository is shallow, ignoring --local"
+msgstr "джерельне сховище є неглибоким, --local ігноровано"
+
+msgid "--local is ignored"
+msgstr "--local ігноровано"
+
+msgid "cannot clone from filtered bundle"
+msgstr "неможливо клонувати з відфільтрованого пакунка"
+
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "не вдалося ініціалізувати сховище, URI пакунка пропущено"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "не вдалося отримати обʼєкти з пакунка URI '%s'"
+
+msgid "failed to fetch advertised bundles"
+msgstr "не вдалося отримати обіцяні пакунки"
+
+msgid "remote transport reported error"
+msgstr "операція віддаленого отримання повідомила про помилку"
+
+#, c-format
+msgid "Remote branch %s not found in upstream %s"
+msgstr "Віддалену гілку %s не знайдено у першоджерельному сховищі %s"
+
+msgid "You appear to have cloned an empty repository."
+msgstr "Здається, ви клонували порожнє сховище."
+
+msgid "git column [<options>]"
+msgstr "git column [<опції>]"
+
+msgid "lookup config vars"
+msgstr "пошук параметрів конфігурації"
+
+msgid "layout to use"
+msgstr "схема розташування"
+
+msgid "maximum width"
+msgstr "максимальна ширина"
+
+msgid "padding space on left border"
+msgstr "відступ по лівому краю"
+
+msgid "padding space on right border"
+msgstr "відступ по правому краю"
+
+msgid "padding space between columns"
+msgstr "відступ між стовпчиками"
+
+msgid "--command must be the first argument"
+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"
+"                       [--split[=<strategy>]] [--reachable | --stdin-packs | "
+"--stdin-commits]\n"
+"                       [--changed-paths] [--[no-]max-new-filters <n>] [--"
+"[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 "директорія"
+
+msgid "the object directory to store the graph"
+msgstr "директорія об’єктів для зберігання графу"
+
+msgid "if the commit-graph is split, only verify the tip file"
+msgstr "якщо коміт-граф розщеплено, перевіряти тільки файл підказок"
+
+#, c-format
+msgid "Could not open commit-graph '%s'"
+msgstr "Не вдалося відкрити коміт-граф \"%s\""
+
+#, c-format
+msgid "unrecognized --split argument, %s"
+msgstr "нерозпізнаний --split аргумент, %s"
+
+#, c-format
+msgid "unexpected non-hex object ID: %s"
+msgstr "неочікуваний не hex ідентифікатор обʼєкта: %s"
+
+#, c-format
+msgid "invalid object: %s"
+msgstr "неприпустимий об’єкт: %s"
+
+#, c-format
+msgid "option `%s' expects a numerical value"
+msgstr "опція \"%s\" очікує числове значення"
+
+msgid "start walk at all refs"
+msgstr "розпочати проходження по всім посиланням"
+
+msgid "scan pack-indexes listed by stdin for commits"
+msgstr "просканувати pack-indexes зазначені через stdin для комітів"
+
+msgid "start walk at commits listed by stdin"
+msgstr "розпочати проходження по всім комітам зазначеним через stdin"
+
+msgid "include all commits already in the commit-graph file"
+msgstr "включити всі коміти, які вже є у файлі коміт-графа"
+
+msgid "enable computation for changed paths"
+msgstr "увімкнути обчислення для змінених шляхів"
+
+msgid "allow writing an incremental commit-graph file"
+msgstr "дозволити запис інкрементного файлу коміт-графа"
+
+msgid "maximum number of commits in a non-base split commit-graph"
+msgstr "максимальна кількість комітів у безбазовому розщепленому коміт-графі"
+
+msgid "maximum ratio between two levels of a split commit-graph"
+msgstr "максимальне співвідношення між двома рівнями розщепленого коміт-графа"
+
+msgid "only expire files older than a given date-time"
+msgstr "видалити лише файли, старіші за вказану дату"
+
+msgid "maximum number of changed-path Bloom filters to compute"
+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 "Збирання комітів з вхідних даних"
+
+msgid "git commit-tree <tree> [(-p <parent>)...]"
+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 "проігноровано дубльований батьківський %s"
+
+#, c-format
+msgid "not a valid object name %s"
+msgstr "невірне ім’я об’єкта %s"
+
+#, c-format
+msgid "git commit-tree: failed to read '%s'"
+msgstr "git commit-tree: не вдалося прочитати \"%s\""
+
+#, c-format
+msgid "git commit-tree: failed to close '%s'"
+msgstr "git commit-tree: не вдалося закрити \"%s\""
+
+msgid "parent"
+msgstr "батько"
+
+msgid "id of a parent commit object"
+msgstr "ідентифікатор обʼєкта батьківського коміту"
+
+msgid "message"
+msgstr "допис"
+
+msgid "commit message"
+msgstr "допис до коміту"
+
+msgid "read commit log message from file"
+msgstr "читати допис до коміту з файлу"
+
+msgid "GPG sign commit"
+msgstr "підписати коміт за допомогою GPG"
+
+msgid "must give exactly one tree"
+msgstr "має бути надано лишень одне дерево"
+
+msgid "git commit-tree: failed to read"
+msgstr "git commit-tree: не вдалося прочитати"
+
+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 ""
+"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 [<опції>] [--] [<визначник шляху>...]"
+
+msgid ""
+"You asked to amend the most recent commit, but doing so would make\n"
+"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"
+"If you wish to commit it anyway, use:\n"
+"\n"
+"    git commit --allow-empty\n"
+"\n"
+msgstr ""
+"Попереднє висмикування зараз порожнє, можливо, через вирішення конфлікту.\n"
+"Якщо ви все одно бажаєте додати його, скористайтесь командою\n"
+"\n"
+"    git commit --allow-empty\n"
+
+msgid "Otherwise, please use 'git rebase --skip'\n"
+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"
+"\n"
+"    git cherry-pick --continue\n"
+"\n"
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    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 "не вдалося розпакувати HEAD обʼєкт дерева"
+
+msgid "No paths with --include/--only does not make sense."
+msgstr "Ніякі шляхи з --include/--only не мають сенсу."
+
+msgid "unable to create temporary index"
+msgstr "не вдалося створити тимчасовий індекс"
+
+msgid "interactive add failed"
+msgstr "інтерактивне додавання не вдалося"
+
+msgid "unable to update temporary index"
+msgstr "не вдалося оновити тимчасовий індекс"
+
+msgid "Failed to update main cache tree"
+msgstr "Не вдалося оновити головне дерево кешу"
+
+msgid "unable to write new_index file"
+msgstr "не вдалося записати new_index файл"
+
+msgid "cannot do a partial commit during a merge."
+msgstr "неможливо зробити частковий коміт під час злиття."
+
+msgid "cannot do a partial commit during a cherry-pick."
+msgstr "неможливо зробити частковий коміт під час висмикування."
+
+msgid "cannot do a partial commit during a rebase."
+msgstr "неможливо зробити частковий коміт під час перебазування."
+
+msgid "cannot read the index"
+msgstr "неможливо прочитати індекс"
+
+msgid "unable to write temporary index file"
+msgstr "не вдалося записати тимчасовий файл індексу"
+
+#, c-format
+msgid "commit '%s' lacks author header"
+msgstr "у коміті \"%s\" немає заголовка автора"
+
+#, c-format
+msgid "commit '%s' has malformed author line"
+msgstr "у коміті \"%s\" невірно сформовано рядок автора"
+
+msgid "malformed --author parameter"
+msgstr "невірно сформований --author параметр"
+
+#, c-format
+msgid "invalid date format: %s"
+msgstr "неприпустимий формат дати: %s"
+
+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\""
+
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr "(читання допису журналу зі стандартного вводу)\n"
+
+msgid "could not read log from standard input"
+msgstr "не вдалося прочитати допис зі стандартного вводу"
+
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "не вдалося прочитати допис з файлу \"%s\""
+
+#, c-format
+msgid "options '%s' and '%s:%s' cannot be used together"
+msgstr "опції \"%s\" та \"%s:%s\" не можна використовувати разом"
+
+msgid "could not read SQUASH_MSG"
+msgstr "не вдалося прочитати SQUASH_MSG"
+
+msgid "could not read MERGE_MSG"
+msgstr "не вдалося прочитати MERGE_MSG"
+
+#, c-format
+msgid "could not open '%s'"
+msgstr "не вдалося відкрити \"%s\""
+
+msgid "could not write commit template"
+msgstr "не вдалося записати шаблон комітів"
+
+#, c-format
+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 ""
+"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"
+"An empty message aborts the commit.\n"
+msgstr ""
+"Будь ласка, введіть допис до коміту для ваших змін. Рядки, що починаються з\n"
+" \"%c\" будуть збережені; ви можете вилучити їх самостійно, якщо захочете.\n"
+"Порожній допис перериває коміт.\n"
+
+msgid ""
+"\n"
+"It looks like you may be committing a merge.\n"
+"If this is not correct, please run\n"
+"\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"
+"It looks like you may be committing a cherry-pick.\n"
+"If this is not correct, please run\n"
+"\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 "%sАвтор:    %.*s <%.*s>"
+
+#, c-format
+msgid "%sDate:      %s"
+msgstr "%sДата:      %s"
+
+#, c-format
+msgid "%sCommitter: %.*s <%.*s>"
+msgstr "%sКомітер: %.*s <%.*s>"
+
+msgid "Cannot read index"
+msgstr "Неможливо прочитати індекс"
+
+msgid "unable to pass trailers to --trailers"
+msgstr "не вдалося передати причепи до --trailers"
+
+msgid "Error building trees"
+msgstr "Помилка при побудові дерев"
+
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+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'"
+msgstr "Неприпустимий режим ігнорування \"%s\""
+
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr "Неприпустимий режим невідстежуваних файлів \"%s\""
+
+msgid "You are in the middle of a merge -- cannot reword."
+msgstr "Ви перебуваєте в процесі злиття -- неможливо перефразувати."
+
+msgid "You are in the middle of a cherry-pick -- cannot reword."
+msgstr "Ви перебуваєте в процесі висмикування -- неможливо перефразувати."
+
+#, c-format
+msgid "reword option of '%s' and path '%s' cannot be used together"
+msgstr ""
+"параметр перефразування \"%s\" і шлях \"%s\" не можуть бути використані разом"
+
+#, c-format
+msgid "reword option of '%s' and '%s' cannot be used together"
+msgstr "опцію перефразування \"%s\" і \"%s\" не можна використовувати разом"
+
+msgid "You have nothing to amend."
+msgstr "Вам немає до чого вносити зміни."
+
+msgid "You are in the middle of a merge -- cannot amend."
+msgstr "Ви перебуваєте в процесі злиття -- неможливо внести зміни."
+
+msgid "You are in the middle of a cherry-pick -- cannot amend."
+msgstr "Ви перебуваєте в процесі висмикування - неможливо внести зміни."
+
+msgid "You are in the middle of a rebase -- cannot amend."
+msgstr "Ви перебуваєте в процесі перебазуавння -- неможливо внести зміни."
+
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr "--reset-author можна використовувати лише з -C, -c або --amend."
+
+#, c-format
+msgid "unknown option: --fixup=%s:%s"
+msgstr "невідомий параметр: --fixup=%s:%s"
+
+#, c-format
+msgid "paths '%s ...' with -a does not make sense"
+msgstr "шляхи \"%s ...\" з -a не мають сенсу"
+
+msgid "show status concisely"
+msgstr "показувати статус стисло"
+
+msgid "show branch information"
+msgstr "показати інформацію про гілку"
+
+msgid "show stash information"
+msgstr "показати інформацію про схов"
+
+msgid "compute full ahead/behind values"
+msgstr "обчислювати повні попереду/позаду значення"
+
+msgid "version"
+msgstr "версія"
+
+msgid "machine-readable output"
+msgstr "машинозчитуваний вивід"
+
+msgid "show status in long format (default)"
+msgstr "показувати статус у повному форматі (за замовчуванням)"
+
+msgid "terminate entries with NUL"
+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 "коли"
+
+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 "не виявляти перейменування"
+
+msgid "detect renames, optionally set similarity index"
+msgstr "виявляти перейменування, опціонально встановлювати індекс схожості"
+
+msgid "Unsupported combination of ignored and untracked-files arguments"
+msgstr ""
+"Непідтримувана комбінація аргументів для ігнорованих та невідстежуваних "
+"файлів"
+
+msgid "suppress summary after successful commit"
+msgstr "не показувати підсумок після успішного коміту"
+
+msgid "show diff in commit message template"
+msgstr "показувати різницю в шаблоні дописа до коміту"
+
+msgid "Commit message options"
+msgstr "Опції дописа до коміту"
+
+msgid "read message from file"
+msgstr "читати текст дописа з файлу"
+
+msgid "author"
+msgstr "автор"
+
+msgid "override author for commit"
+msgstr "перевизначити автора коміту"
+
+msgid "date"
+msgstr "дата"
+
+msgid "override date for commit"
+msgstr "перевизначити дату коміту"
+
+msgid "commit"
+msgstr "коміт"
+
+msgid "reuse and edit message from specified commit"
+msgstr "повторно використати та редагувати допис зі вказаного коміту"
+
+msgid "reuse message from specified commit"
+msgstr "повторно використати допис зі вказаного коміту"
+
+#. TRANSLATORS: Leave "[(amend|reword):]" as-is,
+#. and only translate <commit>.
+#.
+
+msgid "[(amend|reword):]commit"
+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 "автором коміту тепер є я (використовується з -C/-c/--amend)"
+
+msgid "trailer"
+msgstr "причіп"
+
+msgid "add custom trailer(s)"
+msgstr "додати нестандартний причіп"
+
+msgid "add a Signed-off-by trailer"
+msgstr "додати Signed-off-by причіп"
+
+msgid "use specified template file"
+msgstr "використати зазначений файл шаблону"
+
+msgid "force edit of commit"
+msgstr "редагувати коміт примусово"
+
+msgid "include status in commit message template"
+msgstr "включити статус у шаблон дописа до коміту"
+
+msgid "Commit contents options"
+msgstr "Опції вмісту коміту"
+
+msgid "commit all changed files"
+msgstr "закомітити всі змінені файли"
+
+msgid "add specified files to index for commit"
+msgstr "додати вказані файли до індексу для коміту"
+
+msgid "interactively add files"
+msgstr "додавати файли інтерактивно"
+
+msgid "interactively add changes"
+msgstr "додавати зміни інтерактивно"
+
+msgid "commit only specified files"
+msgstr "комітити лише вказані файли"
+
+msgid "bypass pre-commit and commit-msg hooks"
+msgstr "обходити pre-commit та commit-msg гачки"
+
+msgid "show what would be committed"
+msgstr "показати, що буде закомічено"
+
+msgid "amend previous commit"
+msgstr "внести зміни до попереднього коміту"
+
+msgid "bypass post-rewrite hook"
+msgstr "обійти post-rewrite гачок"
+
+msgid "ok to record an empty change"
+msgstr "дозволити записати порожню зміну"
+
+msgid "ok to record a change with an empty message"
+msgstr "дозволити записати зміну з порожнім дописом"
+
+msgid "could not parse HEAD commit"
+msgstr "не вдалося розібрати HEAD коміт"
+
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr "Пошкоджений MERGE_HEAD (%s)"
+
+msgid "could not read MERGE_MODE"
+msgstr "не вдалося прочитати MERGE_MODE"
+
+#, c-format
+msgid "could not read commit message: %s"
+msgstr "не вдалося прочитати допис до коміту: %s"
+
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr "Переривання коміту через порожній допис до коміту.\n"
+
+#, c-format
+msgid "Aborting commit; you did not edit the message.\n"
+msgstr "Переривання коміту; ви не відредагували допис.\n"
+
+#, c-format
+msgid "Aborting commit due to empty commit message body.\n"
+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 "нерозпізнаний аргумент --type, %s"
+
+msgid "only one type at a time"
+msgstr "лише один тип за раз"
+
+msgid "Config file location"
+msgstr "Розташування файлу конфігурації"
+
+msgid "use global config file"
+msgstr "використовувати глобальний файл конфігурації"
+
+msgid "use system config file"
+msgstr "використовувати файл конфігурації системи"
+
+msgid "use repository config file"
+msgstr "використовувати файл конфігурації сховища"
+
+msgid "use per-worktree config file"
+msgstr "використовувати файл конфігурації робочого дерева"
+
+msgid "use given config file"
+msgstr "використовувати наданий файл конфігурації"
+
+msgid "blob-id"
+msgstr "blob-id"
+
+msgid "read config from given blob object"
+msgstr "прочитати конфігурацію з наданого blob-обʼєкту"
+
+msgid "Action"
+msgstr "Дія"
+
+msgid "get value: name [value-pattern]"
+msgstr "отримати значення: назва [шаблон-значення]"
+
+msgid "get all values: key [value-pattern]"
+msgstr "отримати всі значення: ключ [шаблон-значення]"
+
+msgid "get values for regexp: name-regex [value-pattern]"
+msgstr "отримати значення для регвиру: регвир-назви [шаблон-значення]"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "отримати значення для конкретної URL-адреси: розділ[.var] URL-адреса"
+
+msgid "replace all matching variables: name value [value-pattern]"
+msgstr "замінити всі відповідні змінні: назва значення [шаблон-значення]"
+
+msgid "add a new variable: name value"
+msgstr "додати нову змінну: назва значення"
+
+msgid "remove a variable: name [value-pattern]"
+msgstr "видалити змінну: назва [шаблон-значення]"
+
+msgid "remove all matches: name [value-pattern]"
+msgstr "видалити всі збіги: назва [шаблон-значення]"
+
+msgid "rename section: old-name new-name"
+msgstr "перейменувати розділ: стара-назва нова-назва"
+
+msgid "remove a section: name"
+msgstr "видалити розділ: назва"
+
+msgid "list all"
+msgstr "показати всі змінні"
+
+msgid "use string equality when comparing values to 'value-pattern'"
+msgstr ""
+"використовувати рівність строк при порівнянні значень з \"шаблон-значенням\""
+
+msgid "open an editor"
+msgstr "відкрити редактор"
+
+msgid "find the color configured: slot [default]"
+msgstr "знайти налаштований колір: слот [за замовчуванням]"
+
+msgid "find the color setting: slot [stdout-is-tty]"
+msgstr "знайти налаштування кольору: slot [stdout-is-tty]"
+
+msgid "Type"
+msgstr "Тип"
+
+msgid "type"
+msgstr "тип"
+
+msgid "value is given this type"
+msgstr "тип значення"
+
+msgid "value is \"true\" or \"false\""
+msgstr "значення \"true\" або \"false\""
+
+msgid "value is decimal number"
+msgstr "значення десяткове число"
+
+msgid "value is --bool or --int"
+msgstr "значення --bool або --int"
+
+msgid "value is --bool or string"
+msgstr "значення --bool або string"
+
+msgid "value is a path (file or directory name)"
+msgstr "значення шлях (файл або назва директорії)"
+
+msgid "value is an expiry date"
+msgstr "значення - дата закінчення терміну дії"
+
+msgid "Other"
+msgstr "Інше"
+
+msgid "terminate values with NUL byte"
+msgstr "завершити значення байтом NUL"
+
+msgid "show variable names only"
+msgstr "показувати тільки назви змінних"
+
+msgid "respect include directives on lookup"
+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 "невірна кількість аргументів, має бути %d"
+
+#, c-format
+msgid "wrong number of arguments, should be from %d to %d"
+msgstr "невірна кількість аргументів, має бути від %d до %d"
+
+#, c-format
+msgid "invalid key pattern: %s"
+msgstr "неприпустимий шаблон ключа: %s"
+
+#, c-format
+msgid "invalid pattern: %s"
+msgstr "неприпустимий шаблон: %s"
+
+#, c-format
+msgid "failed to format default config value: %s"
+msgstr "не вдалося відформатувати початкове значення конфігурації: %s"
+
+#, c-format
+msgid "cannot parse color '%s'"
+msgstr "не вдалося розібрати колір \"%s\""
+
+msgid "unable to parse default color value"
+msgstr "не вдалося розібрати початкове значення кольору"
+
+msgid "not in a git directory"
+msgstr "не в git директорії"
+
+msgid "writing to stdin is not supported"
+msgstr "запис до stdin не підтримується"
+
+msgid "writing config blobs is not supported"
+msgstr "запис blob конфігурації не підтримується"
+
+#, c-format
+msgid ""
+"# This is Git's per-user configuration file.\n"
+"[user]\n"
+"# Please adapt and uncomment the following lines:\n"
+"#\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 "лише один конфігураційний файл за раз"
+
+msgid "--local can only be used inside a git repository"
+msgstr "--local можна використовувати лише всередині git сховища"
+
+msgid "--blob can only be used inside a git repository"
+msgstr "--blob можна використовувати лише всередині git сховища"
+
+msgid "--worktree can only be used inside a git repository"
+msgstr "--worktree можна використовувати лише всередині git сховища"
+
+msgid "$HOME not set"
+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 "--get-color і тип змінної не узгоджуються"
+
+msgid "only one action at a time"
+msgstr "лише одна дія за раз"
+
+msgid "--name-only is only applicable to --list or --get-regexp"
+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 "--default застосовується лише до --get"
+
+msgid "--fixed-value only applies with 'value-pattern'"
+msgstr "--fixed-value застосовується лише з \"шаблоном-значення\""
+
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "не вдалося прочитати файл конфігурації \"%s\""
+
+msgid "error processing config file(s)"
+msgstr "помилка при обробці файлу(ів) конфігурації"
+
+msgid "editing stdin is not supported"
+msgstr "редагування stdin не підтримується"
+
+msgid "editing blobs is not supported"
+msgstr "редагування blobs не підтримується"
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "неможливо створити конфігураційний файл %s"
+
+#, c-format
+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 "показувати розмір у зручному для читання форматі"
+
+#, c-format
+msgid ""
+"The permissions on your socket directory are too loose; other\n"
+"users may be able to read your cached credentials. Consider running:\n"
+"\n"
+"\tchmod 0700 %s"
+msgstr ""
+"Дозволи на вашу сокет директорію занадто вільні; інші\n"
+"користувачі можуть прочитати ваші кешовані облікові дані. Подумайте про "
+"запуск:\n"
+"\n"
+"\tchmod 0700 %s"
+
+msgid "print debugging messages to stderr"
+msgstr "виводити відлагоджувальні повідомлення в stderr"
+
+msgid "credential-cache--daemon unavailable; no unix socket support"
+msgstr "credential-cache--daemon недоступний; немає підтримки unix-сокетів"
+
+msgid "credential-cache unavailable; no unix socket support"
+msgstr "credential-cache недоступний; немає підтримки unix-сокетів"
+
+#, c-format
+msgid "unable to get credential storage lock in %d ms"
+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 "git describe <blob>"
+
+msgid "head"
+msgstr "head"
+
+msgid "lightweight"
+msgstr "lightweight"
+
+msgid "annotated"
+msgstr "annotated"
+
+#, c-format
+msgid "annotated tag %s not available"
+msgstr "анотований тег %s недоступний"
+
+#, c-format
+msgid "tag '%s' is externally known as '%s'"
+msgstr "тег \"%s\" відомий зовні як \"%s\""
+
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr "жоден тег не збігається точно з \"%s\""
+
+#, c-format
+msgid "No exact match on refs or tags, searching to describe\n"
+msgstr "Немає точного збігу за посиланнями або тегами, пошук для опису\n"
+
+#, c-format
+msgid "finished search at %s\n"
+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 "пройдено через %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 "описати %s\n"
+
+#, c-format
+msgid "Not a valid object name %s"
+msgstr "Неприпустиме ім’я об’єкта %s"
+
+#, c-format
+msgid "%s is neither a commit nor blob"
+msgstr "%s не є commit чи blob"
+
+msgid "find the tag that comes after the commit"
+msgstr "знайти тег, що йде після коміту"
+
+msgid "debug search strategy on stderr"
+msgstr "виводити відлагоджувальні повідомлення стратегії пошуку в stderr"
+
+msgid "use any ref"
+msgstr "використати будь-яке посилання"
+
+msgid "use any tag, even unannotated"
+msgstr "використати будь-який тег, навіть неанотований"
+
+msgid "always use long format"
+msgstr "завжди використовувати довгий формат"
+
+msgid "only follow first parent"
+msgstr "слідувати тільки за першим з батьків"
+
+msgid "only output exact matches"
+msgstr "виводити лише точні збіги"
+
+msgid "consider <n> most recent tags (default: 10)"
+msgstr "враховувати <н> останніх тегів (за замовчуванням: 10)"
+
+msgid "only consider tags matching <pattern>"
+msgstr "враховувати лише теги, що відповідають <шаблону>"
+
+msgid "do not consider tags matching <pattern>"
+msgstr "не враховувати теги, що відповідають <шаблону>"
+
+msgid "show abbreviated commit object as fallback"
+msgstr "показувати скорочений обʼєкт коміту як запасний варіант"
+
+msgid "mark"
+msgstr "позначка"
+
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr ""
+"додати <позначку> до брудного робочого дерева (за замовчуванням: \\”-"
+"dirty\\”)"
+
+msgid "append <mark> on broken working tree (default: \"-broken\")"
+msgstr ""
+"додати <позначку> до пошкодженого робочого дерева (за замовчуванням: \"-"
+"broken\")"
+
+msgid "No names found, cannot describe anything."
+msgstr "Назв не знайдено, неможливо нічого описати."
+
+#, c-format
+msgid "option '%s' and commit-ishes cannot be used together"
+msgstr "опцію \"%s\" не можна використовувати разом з комітоподібними"
+
+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 "вказати місце призначення архіву діагностики"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "вказати суфікс формату strftime для назви файлу"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "вказати вміст архіву діагностики"
+
+msgid "--merge-base only works with two commits"
+msgstr "--merge-base працює лише з двома комітами"
+
+#, c-format
+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"
+
+#, c-format
+msgid "%s...%s: no merge base"
+msgstr "%s...%s: немає бази злиття"
+
+msgid "Not a git repository"
+msgstr "Не є git сховищем"
+
+#, c-format
+msgid "invalid object '%s' given."
+msgstr "надано неприпустимий об’єкт \"%s\"."
+
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr "надано більше двох blob: \"%s\""
+
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr "надано необроблений об’єкт \"%s\"."
+
+#, c-format
+msgid "%s...%s: multiple merge bases, using %s"
+msgstr "%s...%s: кілька баз злиття, використання %s"
+
+msgid "git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"
+msgstr "git difftool [<опції>] [<коміт> [<коміт>]] [--] [<шлях>...]"
+
+#, c-format
+msgid "could not read symlink %s"
+msgstr "не вдалося прочитати символьне посилання %s"
+
+#, c-format
+msgid "could not read symlink file %s"
+msgstr "не вдалося прочитати файл символьного посилання %s"
+
+#, c-format
+msgid "could not read object %s for symlink %s"
+msgstr "не вдалося прочитати об’єкт %s для символьного посилання %s"
+
+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 "обидва файли змінено: \"%s\" і \"%s\"."
+
+msgid "working tree file has been left."
+msgstr "файл робочого дерева було залишено."
+
+#, c-format
+msgid "could not copy '%s' to '%s'"
+msgstr "не вдалося скопіювати \"%s\" в \"%s\""
+
+#, c-format
+msgid "temporary files exist in '%s'."
+msgstr "тимчасові файли існують в \"%s\"."
+
+msgid "you may want to cleanup or recover these."
+msgstr "можливо, ви захочете очистити або відновити їх."
+
+#, c-format
+msgid "failed: %d"
+msgstr "завершилось невдало: %d"
+
+msgid "use `diff.guitool` instead of `diff.tool`"
+msgstr "використовувати \"diff.guitool\" замість \"diff.tool\""
+
+msgid "perform a full-directory diff"
+msgstr "виконати порівняння всіх директорій"
+
+msgid "do not prompt before launching a diff tool"
+msgstr "не запитувати перед запуском diff"
+
+msgid "use symlinks in dir-diff mode"
+msgstr "використовувати символьні посилання у режимі dir-diff"
+
+msgid "tool"
+msgstr "засіб"
+
+msgid "use the specified diff tool"
+msgstr "використовувати вказаний diff засіб"
+
+msgid "print a list of diff tools that may be used with `--tool`"
+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 "вказати нестандартну команду для перегляду різниць"
+
+msgid "passed to `diff`"
+msgstr "передається до \"diff\""
+
+msgid "difftool requires worktree or --no-index"
+msgstr "difftool потребує worktree або --no-index"
+
+msgid "no <tool> given for --tool=<tool>"
+msgstr "не надано <засіб> для --tool=<засіб>"
+
+msgid "no <cmd> given for --extcmd=<cmd>"
+msgstr "не надана <команда> для --extcmd=<команда>"
+
+msgid "git fast-export [<rev-list-opts>]"
+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 "--anonymize-map токен не може бути порожнім"
+
+msgid "show progress after <n> objects"
+msgstr "показати прогрес після <н> обʼєктів"
+
+msgid "select handling of signed tags"
+msgstr "вибрати обробку підписаних тегів"
+
+msgid "select handling of tags that tag filtered objects"
+msgstr "вибрати обробку тегів, якими позначено відфільтровані обʼєкти"
+
+msgid "select handling of commit messages in an alternate encoding"
+msgstr "вибрати обробку дописів до комітів в іншому кодуванні"
+
+msgid "dump marks to this file"
+msgstr "експортувати позначки в цей файл"
+
+msgid "import marks from this file"
+msgstr "імпортувати позначки з цього файлу"
+
+msgid "import marks from this file if it exists"
+msgstr "імпортувати позначки з цього файлу, якщо він існує"
+
+msgid "fake a tagger when tags lack one"
+msgstr "підробляти теггера, коли його не вказано для тега"
+
+msgid "output full tree for each commit"
+msgstr "виводити повне дерево для кожного коміту"
+
+msgid "use the done feature to terminate the stream"
+msgstr "використовувати особливість done для завершення потоку"
+
+msgid "skip output of blob data"
+msgstr "пропускати виведення blob-даних"
+
+msgid "refspec"
+msgstr "визначник посилання"
+
+msgid "apply refspec to exported refs"
+msgstr "застосувати визначник посилання до експортованих посилань"
+
+msgid "anonymize output"
+msgstr "анонімізувати вивід"
+
+msgid "from:to"
+msgstr "від:до"
+
+msgid "convert <from> to <to> in anonymized output"
+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 "показувати оригінальні ідентифікатори обʼєктів blob/комітів"
+
+msgid "label tags with mark ids"
+msgstr "позначати теги ідентифікаторами позначок"
+
+#, c-format
+msgid "Missing from marks for submodule '%s'"
+msgstr "Відсутні \"від\" позначки для підмодуля \"%s\""
+
+#, c-format
+msgid "Missing to marks for submodule '%s'"
+msgstr "Відсутні \"до\" позначки для підмодуля \"%s\""
+
+#, c-format
+msgid "Expected 'mark' command, got %s"
+msgstr "Очікувалась команда \"mark\", отримано %s"
+
+#, c-format
+msgid "Expected 'to' command, got %s"
+msgstr "Очікувалась команда \"to\", отримано %s"
+
+msgid "Expected format name:filename for submodule rewrite option"
+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"
+msgstr "Файл блокування створено, але не звітовано: %s"
+
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git fetch [<опції>] [<сховище> [<визначник посилання>...]]"
+
+msgid "git fetch [<options>] <group>"
+msgstr "git fetch [<опції>] [<група>]"
+
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr "git fetch --multiple [<опції>] [(<сховище> | <група>)...]"
+
+msgid "git fetch --all [<options>]"
+msgstr "git fetch --all [<опції>]"
+
+msgid "fetch.parallel cannot be negative"
+msgstr "fetch.parallel не може бути відʼємним"
+
+msgid "couldn't find remote ref HEAD"
+msgstr "не вдалося знайти посилання для віддаленого HEAD"
+
+#, c-format
+msgid "From %.*s\n"
+msgstr "Від %.*s\n"
+
+#, c-format
+msgid "object %s not found"
+msgstr "об’єкт %s не знайдено"
+
+msgid "[up to date]"
+msgstr "[в актуальному стані]"
+
+msgid "[rejected]"
+msgstr "[відхилено]"
+
+msgid "can't fetch into checked-out branch"
+msgstr "неможливо виконати отримання в активну гілку"
+
+msgid "[tag update]"
+msgstr "[оновлення тегу]"
+
+msgid "unable to update local ref"
+msgstr "не вдалося оновити локальне посилання"
+
+msgid "would clobber existing tag"
+msgstr "зруйнує існуючий тег"
+
+msgid "[new tag]"
+msgstr "[новий тег]"
+
+msgid "[new branch]"
+msgstr "[нова гілка]"
+
+msgid "[new ref]"
+msgstr "[нове посилання]"
+
+msgid "forced update"
+msgstr "примусове оновлення"
+
+msgid "non-fast-forward"
+msgstr "без перемотування вперед"
+
+#, c-format
+msgid "cannot open '%s'"
+msgstr "неможливо відкрити \"%s\""
+
+msgid ""
+"fetch normally indicates which branches had a forced update,\n"
+"but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
+"flag or run 'git config fetch.showForcedUpdates true'"
+msgstr ""
+"fetch зазвичай показує, які гілки було примусово оновлено,\n"
+"але цю перевірку було вимкнено; щоб увімкнути її знову, скористайтесь \"--"
+"show-forced-updates\"\n"
+"або виконайте \"git config fetch.showForcedUpdates true\""
+
+#, c-format
+msgid ""
+"it took %.2f seconds to check forced updates; you can use\n"
+"'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates "
+"false'\n"
+"to avoid this check\n"
+msgstr ""
+"перевірка примусових оновлень зайняла %.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"
+
+#, c-format
+msgid "rejected %s because shallow roots are not allowed to be updated"
+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 "   (%s стануть висячими)"
+
+#, c-format
+msgid "   (%s has become dangling)"
+msgstr "   (%s став висячим)"
+
+msgid "[deleted]"
+msgstr "[видалено]"
+
+msgid "(none)"
+msgstr "(нічого)"
+
+#, c-format
+msgid "refusing to fetch into branch '%s' checked out at '%s'"
+msgstr "відмовлено в отримані в гілку \"%s\", що знаходиться в \"%s\""
+
+#, c-format
+msgid "option \"%s\" value \"%s\" is not valid for %s"
+msgstr "значення \"%s\" опції \"%s\" неприпустиме для %s"
+
+#, c-format
+msgid "option \"%s\" is ignored for %s\n"
+msgstr "опція \"%s\" ігнорується для %s\n"
+
+#, c-format
+msgid "%s is not a valid object"
+msgstr "%s не є припустимим об’єктом"
+
+#, c-format
+msgid "the object %s does not exist"
+msgstr "об’єкт %s не існує"
+
+msgid "multiple branches detected, incompatible with --set-upstream"
+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 ""
+"не встановлено першоджерельне сховище для віддалено відстежуваної гілки"
+
+msgid "not setting upstream for a remote tag"
+msgstr "не встановлено першоджерельне сховище для віддаленого тега"
+
+msgid "unknown branch type"
+msgstr "невідомий тип гілки"
+
+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"
+msgstr "Отримання %s\n"
+
+#, c-format
+msgid "could not fetch %s"
+msgstr "не вдалося отримати %s"
+
+#, c-format
+msgid "could not fetch '%s' (exit code: %d)\n"
+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 "потрібно вказати назву тегу"
+
+msgid "fetch from all remotes"
+msgstr "отримати з усіх віддалених призначень"
+
+msgid "set upstream for git pull/fetch"
+msgstr "встановити першоджерельне сховище для git pull/fetch"
+
+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 ""
+"змінити визначник посилання, щоб помістити всі посилання в 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 "на вимогу"
+
+msgid "control recursive fetching of submodules"
+msgstr "контролювати рекурсивне отримання підмодулів"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "записувати отримані посилання у файл FETCH_HEAD"
+
+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 "refmap"
+
+msgid "specify fetch refmap"
+msgstr "вказати мапу посилань для fetch"
+
+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 "виконати \"maintenance --auto\" після отримуваання"
+
+msgid "check for forced-updates on all updated branches"
+msgstr "перевірити на примусове оновлення для всіх оновлених гілок"
+
+msgid "write the commit-graph after fetching"
+msgstr "записати коміт-граф після отримання"
+
+msgid "accept refspecs from stdin"
+msgstr "приймати визначники посилань з stdin"
+
+msgid "--negotiate-only needs one or more --negotiation-tip=*"
+msgstr "--negotiate-only потребує одного або кількох --negotiation-tip=*"
+
+msgid "negative depth in --deepen is not supported"
+msgstr "відʼємна глибина в --deepen не підтримується"
+
+msgid "--unshallow on a complete repository does not make sense"
+msgstr "--unshallow на повному сховищі не має сенсу"
+
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "не вдалося отримати пакунки з \"%s\""
+
+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 "немає такого віддаленого призначення або віддаленої групи: %s"
+
+msgid "fetching a group and specifying refspecs does not make sense"
+msgstr "отримання групи і вказівка визначників посилань не має сенсу"
+
+msgid "must supply remote when using --negotiate-only"
+msgstr ""
+"необхідно вказати віддалене призначення при використанні --negotiate-only"
+
+msgid "protocol does not support --negotiate-only, exiting"
+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 ""
+"--atomic може бути використано лише при отриманні з одного віддаленого "
+"джерела"
+
+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 "заповнити журнал не більше ніж <н> записами з shortlog"
+
+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>]]"
+msgstr "git for-each-ref [--merged [<коміт>]] [--no-merged [<коміт>]]"
+
+msgid "git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"
+msgstr "git for-each-ref [--contains [<коміт>]] [--no-contains [<коміт>]]"
+
+msgid "quote placeholders suitably for shells"
+msgstr "заповнювачі лапок для shell"
+
+msgid "quote placeholders suitably for perl"
+msgstr "заповнювачі лапок для perl"
+
+msgid "quote placeholders suitably for python"
+msgstr "заповнювачі лапок для python"
+
+msgid "quote placeholders suitably for Tcl"
+msgstr "заповнювачі лапок для Tcl"
+
+msgid "show only <n> matched refs"
+msgstr "показати тільки <н> відповідних посилань"
+
+msgid "respect format colors"
+msgstr "дотримуватися кольорів формату"
+
+msgid "print only refs which points at the given object"
+msgstr "виводити тільки посилання, які вказують на заданий об’єкт"
+
+msgid "print only refs that are merged"
+msgstr "виводити тільки злиті посилання"
+
+msgid "print only refs that are not merged"
+msgstr "виводити тільки не злиті посилання"
+
+msgid "print only refs which contain the commit"
+msgstr "виводити тільки ті посилання, що містять коміт"
+
+msgid "print only refs which don't contain the commit"
+msgstr "виводити тільки ті посилання, що не містять коміту"
+
+msgid "read reference patterns from stdin"
+msgstr "читати шаблони посилань з stdin"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "невідомі аргументи надані через --stdin"
+
+msgid "git for-each-repo --config=<config> [--] <arguments>"
+msgstr "git for-each-repo --config=<конфіг> [--] <аргументи>"
+
+msgid "config"
+msgstr "конфіг"
+
+msgid "config key storing a list of repository paths"
+msgstr "ключ конфігурації, в якому зберігається список шляхів до сховищ"
+
+msgid "missing --config=<config>"
+msgstr "відсутній --config=<конфіг>"
+
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "невірно задано параметр --config=%s"
+
+msgid "unknown"
+msgstr "невідомо"
+
+#. TRANSLATORS: e.g. error in tree 01bfda: <more explanation>
+
+#, c-format
+msgid "error in %s %s: %s"
+msgstr "помилка в %s %s: %s"
+
+#. TRANSLATORS: e.g. warning in tree 01bfda: <more explanation>
+
+#, c-format
+msgid "warning in %s %s: %s"
+msgstr "попередження в %s %s: %s"
+
+#, c-format
+msgid "broken link from %7s %s"
+msgstr "пошкоджене посилання з %7s %s"
+
+msgid "wrong object type in link"
+msgstr "невірний тип об’єкта в посиланні"
+
+#, c-format
+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 "відсутній %s %s"
+
+#, c-format
+msgid "unreachable %s %s"
+msgstr "недосяжний %s %s"
+
+#, c-format
+msgid "dangling %s %s"
+msgstr "висячий %s %s"
+
+msgid "could not create lost-found"
+msgstr "не вдалося створити lost-found"
+
+#, c-format
+msgid "could not write '%s'"
+msgstr "не вдалося записати \"%s\""
+
+#, c-format
+msgid "could not finish '%s'"
+msgstr "не вдалося завершити \"%s\""
+
+#, c-format
+msgid "Checking %s"
+msgstr "Перевірка %s"
+
+#, c-format
+msgid "Checking connectivity (%d objects)"
+msgstr "Перевірка підключення (%d обʼєктів)"
+
+#, c-format
+msgid "Checking %s %s"
+msgstr "Перевірка %s %s"
+
+msgid "broken links"
+msgstr "пошкоджені посилання"
+
+#, c-format
+msgid "root %s"
+msgstr "корінь %s"
+
+#, c-format
+msgid "tagged %s %s (%s) in %s"
+msgstr "з тегом %s %s (%s) в %s"
+
+#, c-format
+msgid "%s: object corrupt or missing"
+msgstr "%s: об’єкт пошкоджений або відсутній"
+
+#, c-format
+msgid "%s: invalid reflog entry %s"
+msgstr "%s: неприпустимий запис журналу посилань %s"
+
+#, c-format
+msgid "Checking reflog %s->%s"
+msgstr "Перевірка журналу посилань %s->%s"
+
+#, c-format
+msgid "%s: invalid sha1 pointer %s"
+msgstr "%s: невірний вказівник sha1 %s"
+
+#, c-format
+msgid "%s: not a commit"
+msgstr "%s не є комітом"
+
+msgid "notice: No default references"
+msgstr "повідомлення: Немає посилань за замовчуванням"
+
+#, c-format
+msgid "%s: hash-path mismatch, found at: %s"
+msgstr "%s: невідповідність хеш/шлях знайдена в: %s"
+
+#, c-format
+msgid "%s: object corrupt or missing: %s"
+msgstr "%s: об’єкт пошкоджений або відсутній: %s"
+
+#, c-format
+msgid "%s: object is of unknown type '%s': %s"
+msgstr "%s: об’єкт невідомого типу \"%s\": %s"
+
+#, c-format
+msgid "%s: object could not be parsed: %s"
+msgstr "%s: неможливо розібрати об’єкт: %s"
+
+#, c-format
+msgid "bad sha1 file: %s"
+msgstr "невірний sha1 файл: %s"
+
+msgid "Checking object directory"
+msgstr "Перевірка директорії об’єкта"
+
+msgid "Checking object directories"
+msgstr "Перевірка директорій обʼєкта"
+
+#, c-format
+msgid "Checking %s link"
+msgstr "Перевірка %s посилання"
+
+#, c-format
+msgid "invalid %s"
+msgstr "неприпустимий %s"
+
+#, c-format
+msgid "%s points to something strange (%s)"
+msgstr "%s вказує на щось дивне (%s)"
+
+#, c-format
+msgid "%s: detached HEAD points at nothing"
+msgstr "%s: відокремлений HEAD вказує на ніщо"
+
+#, c-format
+msgid "notice: %s points to an unborn branch (%s)"
+msgstr "повідомлення: %s вказує на ненароджену гілку (%s)"
+
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Перевірка дерева кеша для \"%s\""
+
+#, c-format
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: невірний sha1 вказівник в cache-tree для %s"
+
+msgid "non-tree in cache-tree"
+msgstr "non-tree в cache-tree"
+
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: невірний sha1 вказівник в resolve-undo для %s"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "не вдалося завантажити rev-index для пакунку \"%s\""
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "неприпустимий rev-index для \"%s\""
+
+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 ""
+"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 "показати недосяжні об’єкти"
+
+msgid "show dangling objects"
+msgstr "показати висячі об’єкти"
+
+msgid "report tags"
+msgstr "звітувати про теги"
+
+msgid "report root nodes"
+msgstr "звітувати про кореневі вузли"
+
+msgid "make index objects head nodes"
+msgstr "побудувати головні вузли об’єктів індексу"
+
+msgid "make reflogs head nodes (default)"
+msgstr "побудувати головні вузли журналу посилань (за замовчуванням)"
+
+msgid "also consider packs and alternate objects"
+msgstr "також розглядати пакунки та запозичені об’єкти"
+
+msgid "check only connectivity"
+msgstr "перевірити лише звʼязність"
+
+msgid "enable more strict checking"
+msgstr "увімкнути більш сувору перевірку"
+
+msgid "write dangling objects in .git/lost-found"
+msgstr "записувати висячі об’єкти в .git/lost-found"
+
+msgid "show progress"
+msgstr "показувати прогрес"
+
+msgid "show verbose names for reachable objects"
+msgstr "показувати докладні назви для доступних об’єктів"
+
+msgid "Checking objects"
+msgstr "Перевірка обʼєктів"
+
+#, c-format
+msgid "%s: object missing"
+msgstr "%s: об’єкт відсутній"
+
+#, c-format
+msgid "invalid parameter: expected sha1, got '%s'"
+msgstr "неприпустимий параметр: очікувалось sha1, надано \"%s\""
+
+msgid "git fsmonitor--daemon start [<options>]"
+msgstr "git fsmonitor--daemon start [<опції>]"
+
+msgid "git fsmonitor--daemon run [<options>]"
+msgstr "git fsmonitor--daemon run [<опції>]"
+
+#, c-format
+msgid "value of '%s' out of range: %d"
+msgstr "значення \"%s\" за межами діапазону: %d"
+
+#, c-format
+msgid "value of '%s' not bool or int: %d"
+msgstr "значення \"%s\" не є bool або int: %d"
+
+#, c-format
+msgid "fsmonitor-daemon is watching '%s'\n"
+msgstr "fsmonitor-daemon стежить за \"%s\"\n"
+
+#, c-format
+msgid "fsmonitor-daemon is not watching '%s'\n"
+msgstr "fsmonitor-daemon не стежить за \"%s\"\n"
+
+#, c-format
+msgid "could not create fsmonitor cookie '%s'"
+msgstr "не вдалося створити fsmonitor cookie \"%s\""
+
+#, c-format
+msgid "fsmonitor: cookie_result '%d' != SEEN"
+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 "не вдалося запустити потік слухача fsmonitor"
+
+msgid "could not start fsmonitor health thread"
+msgstr "не вдалося запустити потік стану fsmonitor"
+
+msgid "could not initialize listener thread"
+msgstr "не вдалося ініціалізувати потік слухача"
+
+msgid "could not initialize health thread"
+msgstr "не вдалося ініціалізувати потік стану"
+
+#, c-format
+msgid "could not cd home '%s'"
+msgstr "не вдалося виконати cd home \"%s\""
+
+#, c-format
+msgid "fsmonitor--daemon is already running '%s'"
+msgstr "fsmonitor--daemon вже запущений \"%s\""
+
+#, c-format
+msgid "running fsmonitor-daemon in '%s'\n"
+msgstr "запуск fsmonitor-daemon в \"%s\"\n"
+
+#, c-format
+msgid "starting fsmonitor-daemon in '%s'\n"
+msgstr "старт fsmonitor-daemon в \"%s\"\n"
+
+msgid "daemon failed to start"
+msgstr "не вдалося запустити демон"
+
+msgid "daemon not online yet"
+msgstr "демон ще не онлайн"
+
+msgid "daemon terminated"
+msgstr "роботу демона припинено"
+
+msgid "detach from console"
+msgstr "від’єднати від консолі"
+
+msgid "use <n> ipc worker threads"
+msgstr "використовувати <н> потоків IPC працівника"
+
+msgid "max seconds to wait for background daemon startup"
+msgstr "максимальна кількість секунд для очікування запуску фонового демона"
+
+#, c-format
+msgid "invalid 'ipc-threads' value (%d)"
+msgstr "невірне значення \"ipc-threads\" (%d)"
+
+#, c-format
+msgid "Unhandled subcommand '%s'"
+msgstr "Необроблена підкоманда \"%s\""
+
+msgid "fsmonitor--daemon not supported on this platform"
+msgstr "fsmonitor--daemon не підтримується на цій платформі"
+
+msgid "git gc [<options>]"
+msgstr "git gc [<опції>]"
+
+#, c-format
+msgid "Failed to fstat %s: %s"
+msgstr "Не вдалося виконати fstat %s: %s"
+
+#, c-format
+msgid "failed to parse '%s' value '%s'"
+msgstr "не вдалося розібрати \"%s\" значення \"%s\""
+
+#, c-format
+msgid "cannot stat '%s'"
+msgstr "неможливо виконати stat \"%s\""
+
+#, c-format
+msgid ""
+"The last gc run reported the following. Please correct the root cause\n"
+"and remove %s\n"
+"Automatic cleanup will not be performed until the file is removed.\n"
+"\n"
+"%s"
+msgstr ""
+"Попередній запуск gc показав наступне. Будь ласка, виправте першопричину\n"
+"і видаліть %s\n"
+"Автоматичне очищення не буде виконано, доки файл не буде вилучено.\n"
+"\n"
+"%s"
+
+msgid "prune unreferenced objects"
+msgstr "видалити об’єкти, на які немає посилань"
+
+msgid "pack unreferenced objects separately"
+msgstr "пакувати об’єкти, на які немає посилань, окремо"
+
+msgid "be more thorough (increased runtime)"
+msgstr "працювати ретельніше (збільшує час виконання)"
+
+msgid "enable auto-gc mode"
+msgstr "увімкнути режим автоматичного збору сміття"
+
+msgid "force running gc even if there may be another gc running"
+msgstr "примусово запускати збирач сміття, навіть якщо інший збирач вже працює"
+
+msgid "repack all other packs except the largest pack"
+msgstr "перепакувати всі пакунки, крім найбільшого"
+
+#, c-format
+msgid "failed to parse gc.logExpiry value %s"
+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 "Автоматичне пакування сховища для оптимальної продуктивності.\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 "--no-schedule не дозволяється"
+
+#, c-format
+msgid "unrecognized --schedule argument '%s'"
+msgstr "нерозпізнаний аргумент --schedule \"%s\""
+
+msgid "failed to write commit-graph"
+msgstr "не вдалося записати граф комітів"
+
+msgid "failed to prefetch remotes"
+msgstr "не вдалося виконати попереднє отримання з віддалених сховищ"
+
+msgid "failed to start 'git pack-objects' process"
+msgstr "не вдалося запустити \"git pack-objects\" процес"
+
+msgid "failed to finish 'git pack-objects' process"
+msgstr "не вдалося завершити \"git pack-objects\" процес"
+
+msgid "failed to write multi-pack-index"
+msgstr "не вдалося записати multi-pack-index"
+
+msgid "'git multi-pack-index expire' failed"
+msgstr "\"git multi-pack-index expire\" завершився невдало"
+
+msgid "'git multi-pack-index repack' failed"
+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 "файл блокування \"%s\" існує, пропуск обслуговування"
+
+#, c-format
+msgid "task '%s' failed"
+msgstr "завдання \"%s\" завершилося невдало"
+
+#, c-format
+msgid "'%s' is not a valid task"
+msgstr "\"%s\" не є припустимим завданням"
+
+#, c-format
+msgid "task '%s' cannot be selected multiple times"
+msgstr "завдання \"%s\" не можна вибрати кілька разів"
+
+msgid "run tasks based on the state of the repository"
+msgstr "запускати завдання на основі стану сховища"
+
+msgid "frequency"
+msgstr "частота"
+
+msgid "run tasks based on frequency"
+msgstr "запускати задачі на основі частоти"
+
+msgid "do not report progress or other information over stderr"
+msgstr "не показувати хід виконання та іншу інформацію в stderr"
+
+msgid "task"
+msgstr "завдання"
+
+msgid "run a specific task"
+msgstr "запустити певне завдання"
+
+msgid "use at most one of --auto and --schedule=<frequency>"
+msgstr "використовуйте щонайбільше одну з опцій --auto та --schedule=<частота>"
+
+#, c-format
+msgid "unable to add '%s' value of '%s'"
+msgstr "не вдалося додати \"%s\" значення до \"%s\""
+
+msgid "return success even if repository was not registered"
+msgstr "повертати успіх, навіть якщо сховище не було зареєстровано"
+
+#, c-format
+msgid "unable to unset '%s' value of '%s'"
+msgstr "не вдалося скинути \"%s\" значення для \"%s\""
+
+#, c-format
+msgid "repository '%s' is not registered"
+msgstr "сховище \"%s\" не зареєстровано"
+
+#, c-format
+msgid "failed to expand path '%s'"
+msgstr "не вдалося розгорнути шлях \"%s\""
+
+msgid "failed to start launchctl"
+msgstr "не вдалося запустити launchctl"
+
+#, c-format
+msgid "failed to create directories for '%s'"
+msgstr "не вдалося створити директорії для \"%s\""
+
+#, c-format
+msgid "failed to bootstrap service %s"
+msgstr "не вдалося розгорнути службу %s"
+
+msgid "failed to create temp xml file"
+msgstr "не вдалося створити тимчасовий xml файл"
+
+msgid "failed to start schtasks"
+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 файл"
+
+msgid "failed to open temporary file"
+msgstr "не вдалося відкрити тимчасовий файл"
+
+msgid "failed to run 'crontab'; your system might not support 'cron'"
+msgstr ""
+"не вдалося запустити \"crontab\"; можливо, ваша система не підтримує \"cron\""
+
+msgid "'crontab' died"
+msgstr "\"crontab\" завершився невдало"
+
+msgid "failed to start systemctl"
+msgstr "не вдалося стартувати systemctl"
+
+msgid "failed to run systemctl"
+msgstr "не вдалося запустити systemctl"
+
+#, c-format
+msgid "failed to delete '%s'"
+msgstr "не вдалося видалити \"%s\""
+
+#, c-format
+msgid "failed to flush '%s'"
+msgstr "не вдалося очистити \"%s\""
+
+#, c-format
+msgid "unrecognized --scheduler argument '%s'"
+msgstr "нерозпізнаний --scheduler аргумент \"%s\""
+
+msgid "neither systemd timers nor crontab are available"
+msgstr "недоступні ні systemd таймери, ні crontab"
+
+#, c-format
+msgid "%s scheduler is not available"
+msgstr "%s планувальник недоступний"
+
+msgid "another process is scheduling background maintenance"
+msgstr "ще один процес планує фонове обслуговування"
+
+msgid "git maintenance start [--scheduler=<scheduler>]"
+msgstr "git maintenance start [--scheduler=<планувальник>]"
+
+msgid "scheduler"
+msgstr "планувальник"
+
+msgid "scheduler to trigger git maintenance run"
+msgstr "планувальник для запуску обслуговування git"
+
+msgid "failed to add repo to global config"
+msgstr "не вдалося додати сховище до глобальної конфігурації"
+
+msgid "git maintenance <subcommand> [<options>]"
+msgstr "git maintenance <підкоманда> [<опції>]"
+
+msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr "git grep [<опції>] [-e] <шаблон> [<ревізія>...] [[--] <шлях>...]"
+
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr "grep: не вдалося створити потік: %s"
+
+#, c-format
+msgid "invalid number of threads specified (%d) for %s"
+msgstr "невірно вказана кількість потоків (%d) для %s"
+
+#. TRANSLATORS: %s is the configuration
+#. variable for tweaking threads, currently
+#. grep.threads
+#.
+
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr "немає підтримки потоків, ігнорування %s"
+
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "не вдалося прочитати дерево (%s)"
+
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr "не вдалося виконати grep для об’єкта типу %s"
+
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr "switch \"%c\" очікує числове значення"
+
+msgid "search in index instead of in the work tree"
+msgstr "шукати в індексі замість робочого дерева"
+
+msgid "find in contents not managed by git"
+msgstr "шукати у вмісті, не індексованому git"
+
+msgid "search in both tracked and untracked files"
+msgstr "шукати як у відстежуваних, так і в невідстежуваних файлах"
+
+msgid "ignore files specified via '.gitignore'"
+msgstr "ігнорувати файли, вказані через \".gitignore\""
+
+msgid "recursively search in each submodule"
+msgstr "шукати рекурсивно в кожному підмодулі"
+
+msgid "show non-matching lines"
+msgstr "показувати рядки, що не збігаються"
+
+msgid "case insensitive matching"
+msgstr "нечутливе до регістру зіставлення"
+
+msgid "match patterns only at word boundaries"
+msgstr "зіставляти шаблони тільки на межі слів"
+
+msgid "process binary files as text"
+msgstr "обробляти бінарні файли як текст"
+
+msgid "don't match patterns in binary files"
+msgstr "не зіставляти шаблони в бінарних файлах"
+
+msgid "process binary files with textconv filters"
+msgstr "обробляти бінарні файли за допомогою textconv фільтрів"
+
+msgid "search in subdirectories (default)"
+msgstr "шукати в піддиректоріях (за замовчуванням)"
+
+msgid "descend at most <depth> levels"
+msgstr "спускатися не більше ніж на <глибина> рівнів"
+
+msgid "use extended POSIX regular expressions"
+msgstr "використовувати розширені POSIX регулярні вирази"
+
+msgid "use basic POSIX regular expressions (default)"
+msgstr "використовувати базові регулярні вирази POSIX (за замовчуванням)"
+
+msgid "interpret patterns as fixed strings"
+msgstr "інтерпретувати шаблони як фіксовані строки"
+
+msgid "use Perl-compatible regular expressions"
+msgstr "використовувати Perl-сумісні регулярні вирази"
+
+msgid "show line numbers"
+msgstr "показувати номери рядків"
+
+msgid "show column number of first match"
+msgstr "показувати номер стовпця першого збігу"
+
+msgid "don't show filenames"
+msgstr "не показувати назви файлів"
+
+msgid "show filenames"
+msgstr "показувати назви файлів"
+
+msgid "show filenames relative to top directory"
+msgstr "показувати назви файлів відносно верхнього каталогу"
+
+msgid "show only filenames instead of matching lines"
+msgstr "показувати лише назви файлів замість відповідних рядків"
+
+msgid "synonym for --files-with-matches"
+msgstr "синонім для --files-with-matches"
+
+msgid "show only the names of files without match"
+msgstr "показувати лише назви файлів без збігу"
+
+msgid "print NUL after filenames"
+msgstr "друкувати NUL після назв файлів"
+
+msgid "show only matching parts of a line"
+msgstr "показувати лише частини рядка, що збігаються"
+
+msgid "show the number of matches instead of matching lines"
+msgstr "показувати кількість збігів замість рядків, що збігаються"
+
+msgid "highlight matches"
+msgstr "виділяти збіги"
+
+msgid "print empty line between matches from different files"
+msgstr "друкувати порожній рядок між збігами з різних файлів"
+
+msgid "show filename only once above matches from same file"
+msgstr "показувати назву файлу лише один раз над збігами з того файлу"
+
+msgid "show <n> context lines before and after matches"
+msgstr "показувати <н> рядків до і після збігу"
+
+msgid "show <n> context lines before matches"
+msgstr "показувати <н> рядків до збігу"
+
+msgid "show <n> context lines after matches"
+msgstr "показувати <н> рядків після збігу"
+
+msgid "use <n> worker threads"
+msgstr "використати <н> робочих потоків"
+
+msgid "shortcut for -C NUM"
+msgstr "скорочення для -C номер"
+
+msgid "show a line with the function name before matches"
+msgstr "показувати рядок з назвою функції перед збігами"
+
+msgid "show the surrounding function"
+msgstr "показати навколишню функцію"
+
+msgid "read patterns from file"
+msgstr "зчитувати шаблони з файлу"
+
+msgid "match <pattern>"
+msgstr "зіставляти <шаблон>"
+
+msgid "combine patterns specified with -e"
+msgstr "об’єднати шаблони, вказані через -e"
+
+msgid "indicate hit with exit status without output"
+msgstr "позначати збіг кодом виходу без виводу"
+
+msgid "show only matches from files that match all patterns"
+msgstr "показувати збіги лише з файлів, які відповідають усім шаблонам"
+
+msgid "pager"
+msgstr "пейджер"
+
+msgid "show matching files in the pager"
+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 "шаблон не надано"
+
+msgid "--no-index or --untracked cannot be used with revs"
+msgstr "--no-index або --untracked не можна використовувати з ревізіями"
+
+#, c-format
+msgid "unable to resolve revision: %s"
+msgstr "не вдалося розвʼязати ревізію: %s"
+
+msgid "--untracked not supported with --recurse-submodules"
+msgstr "--untracked не підтримується з --recurse-submodules"
+
+msgid "invalid option combination, ignoring --threads"
+msgstr "неприпустима комбінація опцій, ігнорування --threads"
+
+msgid "no threads support, ignoring --threads"
+msgstr "немає підтримки потоків, ігнорування --threads"
+
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr "вказано неприпустиму кількість потоків (%d)"
+
+msgid "--open-files-in-pager only works on the worktree"
+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 "надані як --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 "git hash-object [-t <тип>] [-w] --stdin-paths [--no-filters]"
+
+msgid "object type"
+msgstr "тип обʼєкта"
+
+msgid "write the object into the object database"
+msgstr "записати об’єкт до бази даних об’єктів"
+
+msgid "read the object from stdin"
+msgstr "прочитати об’єкт з stdin"
+
+msgid "store file as is without filters"
+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 "оброблювати файл, наче він з цього шляху"
+
+msgid "print all available commands"
+msgstr "показати всі доступні команди"
+
+msgid "show external commands in --all"
+msgstr "показати зовнішні команди в --all"
+
+msgid "show aliases in --all"
+msgstr "показати псевдоніми в --all"
+
+msgid "exclude guides"
+msgstr "виключити посібники"
+
+msgid "show man page"
+msgstr "показати сторінку керівництва користувача"
+
+msgid "show manual in web browser"
+msgstr "показати сторінку керівництва користувача в веб-браузері"
+
+msgid "show info page"
+msgstr "показати інформаційну сторінку"
+
+msgid "print command description"
+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>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<команда>|<док>]"
+
+#, c-format
+msgid "unrecognized help format '%s'"
+msgstr "нерозпізнаний формат довідки \"%s\""
+
+msgid "Failed to start emacsclient."
+msgstr "Не вдалося запустити emacsclient."
+
+msgid "Failed to parse emacsclient version."
+msgstr "Не вдалося розібрати версію emacsclient."
+
+#, c-format
+msgid "emacsclient version '%d' too old (< 22)."
+msgstr "версія emacsclient \"%d\" застаріла (< 22)."
+
+#, c-format
+msgid "failed to exec '%s'"
+msgstr "не вдалося виконати \"%s\""
+
+#, c-format
+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 "\"%s\": невідомий переглядач керівництва користувача."
+
+msgid "no man viewer handled the request"
+msgstr "жоден з переглядачів керівництва користувача не обробив запит"
+
+msgid "no info viewer handled the request"
+msgstr "жоден з переглядачів інформації не обробив запит"
+
+#, c-format
+msgid "'%s' is aliased to '%s'"
+msgstr "\"%s\" є псевдонімом для \"%s\""
+
+#, c-format
+msgid "bad alias.%s string: %s"
+msgstr "невірний псевдонім.%s рядок: %s"
+
+#, c-format
+msgid "the '%s' option doesn't take any non-option arguments"
+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 "використання: %s%s"
+
+msgid "'git help config' for more information"
+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 "мовчки ігнорувати відсутній <назва-гачка>"
+
+msgid "file to read into hooks' stdin"
+msgstr "файл, з якого читати stdin хука"
+
+#, c-format
+msgid "object type mismatch at %s"
+msgstr "не співпадає тип обʼєкта для %s"
+
+#, c-format
+msgid "did not receive expected object %s"
+msgstr "очікуваних обʼєктів не отримано %s"
+
+#, c-format
+msgid "object %s: expected type %s, found %s"
+msgstr "обʼєкт %s: очікувався тип %s, знайдено %s"
+
+#, c-format
+msgid "cannot fill %d byte"
+msgid_plural "cannot fill %d bytes"
+msgstr[0] "не вдається заповнити %d байт"
+msgstr[1] "не вдається заповнити %d байти"
+msgstr[2] "не вдається заповнити %d байтів"
+
+msgid "early EOF"
+msgstr "ранній EOF"
+
+msgid "read error on input"
+msgstr "помилка зчитування на вході"
+
+msgid "used more bytes than were available"
+msgstr "використано більше байтів, ніж було доступно"
+
+msgid "pack too large for current definition of off_t"
+msgstr "пакунок занадто великий для поточного визначення off_t"
+
+#, c-format
+msgid "pack exceeds maximum allowed size (%s)"
+msgstr "пакунок перевищує максимально дозволений розмір (%s)"
+
+msgid "pack signature mismatch"
+msgstr "не співпадає підпис пакунка"
+
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr "версія пакунка %<PRIu32> не підтримується"
+
+#, c-format
+msgid "pack has bad object at offset %<PRIuMAX>: %s"
+msgstr "пакунок має невірний обʼєкт зі зміщенням %<PRIuMAX>: %s"
+
+#, c-format
+msgid "inflate returned %d"
+msgstr "розпаковувач повернув %d"
+
+msgid "offset value overflow for delta base object"
+msgstr "переповнення значення зсуву для обʼєкту дельти з базою"
+
+msgid "delta base offset is out of bound"
+msgstr "зсув дельти з базою виходить за межі"
+
+#, c-format
+msgid "unknown object type %d"
+msgstr "невідомий тип обʼєкта %d"
+
+msgid "cannot pread pack file"
+msgstr "неможливо прочитати файл пакунка"
+
+#, c-format
+msgid "premature end of pack file, %<PRIuMAX> byte missing"
+msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
+msgstr[0] "передчасний кінець файлу пакунка, %<PRIuMAX> байт відсутній"
+msgstr[1] "передчасний кінець файлу пакунка, %<PRIuMAX> байта відсутні"
+msgstr[2] "передчасний кінець файлу пакунка, %<PRIuMAX> байтів відсутні"
+
+msgid "serious inflate inconsistency"
+msgstr "серйозне неспівпадіння під час розпакування"
+
+#, c-format
+msgid "SHA1 COLLISION FOUND WITH %s !"
+msgstr "ВИЯВЛЕНО SHA1 КОЛІЗІЮ З %s!"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "не вдалося прочитати %s"
+
+#, c-format
+msgid "cannot read existing object info %s"
+msgstr "неможливо прочитати інформацію про існуючий об’єкт %s"
+
+#, c-format
+msgid "cannot read existing object %s"
+msgstr "неможливо прочитати існуючий об’єкт %s"
+
+#, c-format
+msgid "invalid blob object %s"
+msgstr "неприпустимий об’єкт blob %s"
+
+msgid "fsck error in packed object"
+msgstr "помилка fsck у запакованому обʼєкті"
+
+#, c-format
+msgid "Not all child objects of %s are reachable"
+msgstr "Не всі дочірні об’єкти %s доступні"
+
+msgid "failed to apply delta"
+msgstr "не вдалося застосувати дельту"
+
+msgid "Receiving objects"
+msgstr "Отримання об’єктів"
+
+msgid "Indexing objects"
+msgstr "Індексація об’єктів"
+
+msgid "pack is corrupted (SHA1 mismatch)"
+msgstr "пакунок пошкоджено (SHA1 не співпадає)"
+
+msgid "cannot fstat packfile"
+msgstr "неможливо зробити fstat файла пакунка"
+
+msgid "pack has junk at the end"
+msgstr "мотлох наприкінці пакунка"
+
+msgid "confusion beyond insanity in parse_pack_objects()"
+msgstr "плутанина на межі пекельного борошна в parse_pack_objects()"
+
+msgid "Resolving deltas"
+msgstr "Розв’язання дельт"
+
+#, c-format
+msgid "unable to create thread: %s"
+msgstr "не вдалося створити потік: %s"
+
+msgid "confusion beyond insanity"
+msgstr "плутанина на межі пекельного борошна"
+
+#, c-format
+msgid "completed with %d local object"
+msgid_plural "completed with %d local objects"
+msgstr[0] "завершено з %d локальним об’єктом"
+msgstr[1] "завершено з %d локальними об’єктами"
+msgstr[2] "завершено з %d локальними об’єктами"
+
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr "Неочікувана контрольна сума наприкінці %s (пошкодження диска?)"
+
+#, c-format
+msgid "pack has %d unresolved delta"
+msgid_plural "pack has %d unresolved deltas"
+msgstr[0] "пакунок має %d нерозвʼязану дельту"
+msgstr[1] "пакунок має %d нерозвʼязаних дельти"
+msgstr[2] "пакунок має %d нерозвʼязаних дельт"
+
+#, c-format
+msgid "unable to deflate appended object (%d)"
+msgstr "не вдалося запакувати доданий об’єкт (%d)"
+
+#, c-format
+msgid "local object %s is corrupt"
+msgstr "локальний обʼєкт %s пошкоджено"
+
+#, c-format
+msgid "packfile name '%s' does not end with '.%s'"
+msgstr "ім’я файла пакунка '%s' не закінчується на '.%s'"
+
+#, c-format
+msgid "cannot write %s file '%s'"
+msgstr "неможливо записати %s файл '%s'"
+
+#, c-format
+msgid "cannot close written %s file '%s'"
+msgstr "неможливо закрити записаний %s файл '%s'"
+
+#, c-format
+msgid "unable to rename temporary '*.%s' file to '%s'"
+msgstr "не вдається перейменувати тимчасовий файл '*.%s' на '%s'"
+
+msgid "error while closing pack file"
+msgstr "помилка під час закриття файлу пакунка"
+
+#, c-format
+msgid "bad pack.indexVersion=%<PRIu32>"
+msgstr "невірний pack.indexVersion=%<PRIu32>"
+
+#, c-format
+msgid "Cannot open existing pack file '%s'"
+msgstr "Неможливо відкрити існуючий файл пакунка '%s"
+
+#, c-format
+msgid "Cannot open existing pack idx file for '%s'"
+msgstr "Неможливо відкрити існуючий індексний файл пакунка для '%s"
+
+#, c-format
+msgid "non delta: %d object"
+msgid_plural "non delta: %d objects"
+msgstr[0] "не дельта: %d об’єкт"
+msgstr[1] "не дельта: %d об’єкта"
+msgstr[2] "не дельта: %d об’єктів"
+
+#, c-format
+msgid "chain length = %d: %lu object"
+msgid_plural "chain length = %d: %lu objects"
+msgstr[0] "довжина ланцюжка = %d: %lu об’єкт"
+msgstr[1] "довжина ланцюжка = %d: %lu об’єкти"
+msgstr[2] "довжина ланцюжка = %d: %lu об’єктів"
+
+msgid "Cannot come back to cwd"
+msgstr "Неможливо повернутися до поточної робочої директорії"
+
+#, c-format
+msgid "bad %s"
+msgstr "невірний %s"
+
+#, c-format
+msgid "unknown hash algorithm '%s'"
+msgstr "невідомий хеш-алгоритм '%s'"
+
+msgid "--stdin requires a git repository"
+msgstr "--stdin потребує наявності git сховища"
+
+msgid "--verify with no packfile name given"
+msgstr "--verify без зазначення имені файла пакунка"
+
+msgid "fsck error in pack objects"
+msgstr "помилка fsck в об’єктах пакунка"
+
+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 "дозволи"
+
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr "вказати, що git сховище буде спільним для кількох користувачів"
+
+msgid "override the name of the initial branch"
+msgstr "перевизначити назву початкової гілки"
+
+msgid "hash"
+msgstr "хеш"
+
+msgid "specify the hash algorithm to use"
+msgstr "вказати, який алгоритм хешування використовувати"
+
+#, c-format
+msgid "cannot mkdir %s"
+msgstr "не вдалося виконати mkdir %s"
+
+#, c-format
+msgid "cannot chdir to %s"
+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\""
+
+msgid "--separate-git-dir incompatible with bare repository"
+msgstr "--separate-git-dir несумісна з порожнім сховищем"
+
+msgid ""
+"git interpret-trailers [--in-place] [--trim-empty]\n"
+"                       [(--trailer <token>[(=|:)<value>])...]\n"
+"                       [--parse] [<file>...]"
+msgstr ""
+"git interpret-trailers [--in-place] [--trim-empty]\n"
+"                       [(--trailer <токен>[(=|:)<значення>])...]\n"
+"                       [--parse] [<файл>...]"
+
+msgid "edit files in place"
+msgstr "редагувати файли на місцях"
+
+msgid "trim empty trailers"
+msgstr "обрізати порожні причепи"
+
+msgid "where to place the new trailer"
+msgstr "де розмістити новий причіп"
+
+msgid "action if trailer already exists"
+msgstr "що робити, якщо причіп вже існує"
+
+msgid "action if trailer is missing"
+msgstr "що робити, якщо причіп відсутній"
+
+msgid "output only the trailers"
+msgstr "виводити лише причепи"
+
+msgid "do not apply config rules"
+msgstr "не застосовувати правила конфігурації"
+
+msgid "join whitespace-continued values"
+msgstr "об’єднати значення, що продовжуються через пробіл"
+
+msgid "set parsing options"
+msgstr "встановити параметри розбору"
+
+msgid "do not treat --- specially"
+msgstr "не обробляти --- особливим чином"
+
+msgid "trailer(s) to add"
+msgstr "причіп(и) для додавання"
+
+msgid "--trailer with --only-input does not make sense"
+msgstr "--trailer з --only-input не має сенсу"
+
+msgid "no input file given for in-place editing"
+msgstr "не надано вхідного файлу для редагування на місці"
+
+msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
+msgstr "git log [<опції>] [<діапазон-ревізій>] [[--] <шлях>...]"
+
+msgid "git show [<options>] <object>..."
+msgstr "git show [<опції>] <обʼєкт>..."
+
+#, c-format
+msgid "invalid --decorate option: %s"
+msgstr "неприпустима --decorate опція: %s"
+
+msgid "suppress diff output"
+msgstr "приховати вивід diff"
+
+msgid "show source"
+msgstr "показати джерело"
+
+msgid "clear all previously-defined decoration filters"
+msgstr "очистити всі раніше визначені фільтри оздоблення"
+
+msgid "only decorate refs that match <pattern>"
+msgstr "оздоблювати лише посилання, що відповідають <шаблону>"
+
+msgid "do not decorate refs that match <pattern>"
+msgstr "не оздоблювати посилання, що відповідають <шаблону>"
+
+msgid "decorate options"
+msgstr "опції оздоблення"
+
+msgid ""
+"trace the evolution of line range <start>,<end> or function :<funcname> in "
+"<file>"
+msgstr ""
+"простежити еволюцію діапазону рядків <початок>,<кінець> або функції :<назва-"
+"функції> в <файлі>"
+
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "нерозпізнаний аргумент: %s"
+
+msgid "-L<range>:<file> cannot be used with pathspec"
+msgstr "-L<діапазон>:<файл> не можна використовувати з визначником шляху"
+
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr "Кінцевий результат: %d %s\n"
+
+msgid "unable to create temporary object directory"
+msgstr "не вдалося створити тимчасову директорію об’єкта"
+
+#, c-format
+msgid "git show %s: bad file"
+msgstr "git show %s: невірний файл"
+
+#, c-format
+msgid "could not read object %s"
+msgstr "не вдалося прочитати об’єкт %s"
+
+#, c-format
+msgid "unknown type: %d"
+msgstr "невідомий тип: %d"
+
+#, c-format
+msgid "%s: invalid cover from description mode"
+msgstr "%s: невірна обкладинка з режиму опису"
+
+msgid "format.headers without value"
+msgstr "format.headers без значення"
+
+#, c-format
+msgid "cannot open patch file %s"
+msgstr "не вдається відкрити файл латки %s"
+
+msgid "need exactly one range"
+msgstr "потрібен лишень один діапазон"
+
+msgid "not a range"
+msgstr "не діапазон"
+
+msgid "cover letter needs email format"
+msgstr "супровідний лист має бути у форматі електронної пошти"
+
+msgid "failed to create cover-letter file"
+msgstr "не вдалося створити файл супровідного листа"
+
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr "неприпустимий in-reply-to: %s"
+
+msgid "git format-patch [<options>] [<since> | <revision-range>]"
+msgstr "git format-patch [<опції>] [<відколи> | <діапазон-ревізій>]"
+
+msgid "two output directories?"
+msgstr "дві вихідні директорії?"
+
+#, c-format
+msgid "unknown commit %s"
+msgstr "невідомий коміт %s"
+
+#, c-format
+msgid "failed to resolve '%s' as a valid ref"
+msgstr "не вдалося розпізнати \"%s\" як припустиме посилання"
+
+msgid "could not find exact merge base"
+msgstr "не вдалося знайти точну базу для злиття"
+
+msgid ""
+"failed to get upstream, if you want to record base commit automatically,\n"
+"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 "базовий коміт має бути предком списку ревізій"
+
+msgid "base commit shouldn't be in revision list"
+msgstr "базового коміту не має бути в списку ревізій"
+
+msgid "cannot get patch id"
+msgstr "неможливо отримати ідентифікатор латки"
+
+msgid "failed to infer range-diff origin of current series"
+msgstr "не вдалося визначити походження різниці діапазонів поточного ряду"
+
+#, c-format
+msgid "using '%s' as range-diff origin of current series"
+msgstr "використання \"%s\" як походження різниці діапазонів поточного ряду"
+
+msgid "use [PATCH n/m] even with a single patch"
+msgstr "використовуйте [PATCH n/m] навіть з однією латкою"
+
+msgid "use [PATCH] even with multiple patches"
+msgstr "використовуйте [PATCH] навіть з кількома латками"
+
+msgid "print patches to standard out"
+msgstr "вивести латки на стандартний вивід"
+
+msgid "generate a cover letter"
+msgstr "скласти супровідний лист"
+
+msgid "use simple number sequence for output file names"
+msgstr "використати просту послідовність чисел для назв вихідних файлів"
+
+msgid "sfx"
+msgstr "суфікс"
+
+msgid "use <sfx> instead of '.patch'"
+msgstr "використати <суфікс> замість \".patch\""
+
+msgid "start numbering patches at <n> instead of 1"
+msgstr "почати нумерацію латок з <н> замість 1"
+
+msgid "reroll-count"
+msgstr "кількість перекидань"
+
+msgid "mark the series as Nth re-roll"
+msgstr "позначити ряд як N-не перекидання"
+
+msgid "max length of output filename"
+msgstr "максимальна довжина назви вихідного файлу"
+
+msgid "use [RFC PATCH] instead of [PATCH]"
+msgstr "використати [RFC PATCH] замість [PATCH]"
+
+msgid "cover-from-description-mode"
+msgstr "cover-from-description-mode"
+
+msgid "generate parts of a cover letter based on a branch's description"
+msgstr "скласти частини супровідного листа на основі опису гілки"
+
+msgid "use [<prefix>] instead of [PATCH]"
+msgstr "використати [<префікс>] замість [PATCH]"
+
+msgid "store resulting files in <dir>"
+msgstr "зберегти результуючі файли в <директорії>"
+
+msgid "don't strip/add [PATCH]"
+msgstr "не видаляти/додавати [PATCH]"
+
+msgid "don't output binary diffs"
+msgstr "не виводити бінарні різниці"
+
+msgid "output all-zero hash in From header"
+msgstr "вивести хеш з усіма нулями в заголовку From"
+
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+"не включати латки, які мають відповідні коміти в першоджерельному сховищі"
+
+msgid "show patch format instead of default (patch + stat)"
+msgstr "показати формат латки замість стандартного (латка + підсумок)"
+
+msgid "Messaging"
+msgstr "Повідомлення"
+
+msgid "header"
+msgstr "заголовок"
+
+msgid "add email header"
+msgstr "додати заголовок листа"
+
+msgid "email"
+msgstr "електронна адреса"
+
+msgid "add To: header"
+msgstr "додати To: заголовок"
+
+msgid "add Cc: header"
+msgstr "додати Cc: заголовок"
+
+msgid "ident"
+msgstr "особистість"
+
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr ""
+"встановити From адресу в <особистість> (або особистість комітера, якщо "
+"відсутня)"
+
+msgid "message-id"
+msgstr "ідентифікатор-повідомлення"
+
+msgid "make first mail a reply to <message-id>"
+msgstr "зробити перший лист відповіддю на <id-повідомлення>"
+
+msgid "boundary"
+msgstr "межа"
+
+msgid "attach the patch"
+msgstr "прикріпити латку"
+
+msgid "inline the patch"
+msgstr "вставити латку"
+
+msgid "enable message threading, styles: shallow, deep"
+msgstr "увімкнути потік повідомлень, стилі: дрібний, глибокий"
+
+msgid "signature"
+msgstr "підпис"
+
+msgid "add a signature"
+msgstr "додати підпис"
+
+msgid "base-commit"
+msgstr "базовий коміт"
+
+msgid "add prerequisite tree info to the patch series"
+msgstr "додати інформацію про дерево передумов до серії латок"
+
+msgid "add a signature from a file"
+msgstr "додати підпис з файлу"
+
+msgid "don't print the patch filenames"
+msgstr "не виводити назви файлів латок"
+
+msgid "show progress while generating patches"
+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 "відсоток, за яким зважується створення"
+
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "показувати in-body From: навіть якщо він ідентичний заголовку листа"
+
+#, c-format
+msgid "invalid ident line: %s"
+msgstr "неприпустимий рядок особистості: %s"
+
+msgid "--name-only does not make sense"
+msgstr "--name-only не має сенсу"
+
+msgid "--name-status does not make sense"
+msgstr "--name-status не має сенсу"
+
+msgid "--check does not make sense"
+msgstr "--check не має сенсу"
+
+msgid "--remerge-diff does not make sense"
+msgstr "--remerge-diff не має сенсу"
+
+#, c-format
+msgid "could not create directory '%s'"
+msgstr "не вдалося створити директорію \"%s\""
+
+msgid "--interdiff requires --cover-letter or single patch"
+msgstr "--interdiff вимагає --cover-letter або окремої латки"
+
+msgid "Interdiff:"
+msgstr "Різниця з попередньою серією латок:"
+
+#, c-format
+msgid "Interdiff against v%d:"
+msgstr "Різниця з v%d:"
+
+msgid "--range-diff requires --cover-letter or single patch"
+msgstr "--range-diff потребує --cover-letter або окремої латки"
+
+msgid "Range-diff:"
+msgstr "Різниця діапазону з попередньою серією латок:"
+
+#, c-format
+msgid "Range-diff against v%d:"
+msgstr "Різниця діапазону з v%d:"
+
+#, c-format
+msgid "unable to read signature file '%s'"
+msgstr "не вдалося прочитати файл підпису \"%s\""
+
+msgid "Generating patches"
+msgstr "Створення латок"
+
+msgid "failed to create output files"
+msgstr "не вдалося створити вихідні файли"
+
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+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-files формат: елемент \"%s\" не починається з \"(\""
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "невірний ls-files формат: елемент \"%s\" не закінчується на \")\""
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "невірний ls-files формат: %%%.*s"
+
+msgid "git ls-files [<options>] [<file>...]"
+msgstr "git ls-files [<опції>] [<файл>...]"
+
+msgid "separate paths with the NUL character"
+msgstr "відокремити шляхи символом NUL"
+
+msgid "identify the file status with tags"
+msgstr "визначити стан файлу за допомогою тегів"
+
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr "використати малі літери для \"вважати незмінними\" файлів"
+
+msgid "use lowercase letters for 'fsmonitor clean' files"
+msgstr "використати малі літери для \"fsmonitor clean\" файлів"
+
+msgid "show cached files in the output (default)"
+msgstr "показати кешовані файли у виводі (за замовчуванням)"
+
+msgid "show deleted files in the output"
+msgstr "показати видалені файли у виводі"
+
+msgid "show modified files in the output"
+msgstr "показати змінені файли у виводі"
+
+msgid "show other files in the output"
+msgstr "показати інші файли у виводі"
+
+msgid "show ignored files in the output"
+msgstr "показати ігноровані файли у виводі"
+
+msgid "show staged contents' object name in the output"
+msgstr "показати назву обʼєкта індексованого вмісту у виводі"
+
+msgid "show files on the filesystem that need to be removed"
+msgstr "показати файли файлової системи, які потрібно видалити"
+
+msgid "show 'other' directories' names only"
+msgstr "показати тільки назви \"інших\" директорій"
+
+msgid "show line endings of files"
+msgstr "показати закінчення рядків файлів"
+
+msgid "don't show empty directories"
+msgstr "не показувати порожні директорії"
+
+msgid "show unmerged files in the output"
+msgstr "показати не злиті файли у виводі"
+
+msgid "show resolve-undo information"
+msgstr "показати resolve-undo інформацію"
+
+msgid "skip files matching pattern"
+msgstr "пропустити файли, які відповідають шаблону"
+
+msgid "read exclude patterns from <file>"
+msgstr "читати шаблони виключення з <файлу>"
+
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr "читати додаткові шаблони виключення для кожної директорії з <файлу>"
+
+msgid "add the standard git exclusions"
+msgstr "додати стандартні git виключення"
+
+msgid "make the output relative to the project top directory"
+msgstr "зробити виведення відносно верхньої директорії проекту"
+
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr "якщо якогось <файлу> немає в індексі, вважати це помилкою"
+
+msgid "tree-ish"
+msgstr "деревоподібне-джерело"
+
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+"вдавати, що шляхи, видалені після <деревоподібного-джерела>, все ще присутні"
+
+msgid "show debugging data"
+msgstr "показати дані відлагодження"
+
+msgid "suppress duplicate entries"
+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 ""
+"--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 "не виводити віддалену URL-адресу"
+
+msgid "exec"
+msgstr "виконавчий файл"
+
+msgid "path of git-upload-pack on the remote host"
+msgstr "шлях до git-upload-pack на віддаленому сервері"
+
+msgid "limit to tags"
+msgstr "обмежити до тегів"
+
+msgid "limit to heads"
+msgstr "обмежити до голів"
+
+msgid "do not show peeled tags"
+msgstr "не показувати очищені теги"
+
+msgid "take url.<base>.insteadOf into account"
+msgstr "враховувати url.<база>.insteadOf"
+
+msgid "exit with exit code 2 if no matching refs are found"
+msgstr "вийти з кодом виходу 2, якщо не знайдено відповідних посилань"
+
+msgid "show underlying ref in addition to the object pointed by it"
+msgstr "показувати базове посилання на додаток до об’єкта, на який воно вказує"
+
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git ls-tree [<опції>] <деревоподібне-джерело> [<шлях>...]"
+
+#, c-format
+msgid "bad ls-tree format: element '%s' does not start with '('"
+msgstr "невірний формат ls-tree: елемент \"%s\" не починається з \"(\""
+
+#, c-format
+msgid "bad ls-tree format: element '%s' does not end in ')'"
+msgstr "невірний формат ls-tree: елемент \"%s\" не закінчується на \")\""
+
+#, c-format
+msgid "bad ls-tree format: %%%.*s"
+msgstr "невірний формат ls-tree: %%%.*s"
+
+msgid "only show trees"
+msgstr "показувати тільки дерева"
+
+msgid "recurse into subtrees"
+msgstr "рекурсивно в піддеревах"
+
+msgid "show trees when recursing"
+msgstr "відображати дерева при рекурсії"
+
+msgid "terminate entries with NUL byte"
+msgstr "завершувати записи байтом NUL"
+
+msgid "include object size"
+msgstr "включити розмір об’єкта"
+
+msgid "list only filenames"
+msgstr "показувати лише назви файлів"
+
+msgid "list only objects"
+msgstr "показати лише обʼєкти"
+
+msgid "use full path names"
+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 не можна комбінувати з іншими опціями зміни формату"
+
+#. TRANSLATORS: keep <> in "<" mail ">" info.
+
+msgid "git mailinfo [<options>] <msg> <patch> < mail >info"
+msgstr "git mailinfo [<опції>] <допис> <латка> < mail >info"
+
+msgid "keep subject"
+msgstr "не змінювати тему"
+
+msgid "keep non patch brackets in subject"
+msgstr "зберігати дужки, що не стосуються латок, в темі"
+
+msgid "copy Message-ID to the end of commit message"
+msgstr "копіювати Message-ID в кінець допису до коміту"
+
+msgid "re-code metadata to i18n.commitEncoding"
+msgstr "перекодувати метадані в i18n.commitEncoding"
+
+msgid "disable charset re-coding of metadata"
+msgstr "вимкнути перекодування метаданих"
+
+msgid "encoding"
+msgstr "кодування"
+
+msgid "re-code metadata to this encoding"
+msgstr "перекодувати метадані в це кодування"
+
+msgid "use scissors"
+msgstr "використовувати ножиці"
+
+msgid "<action>"
+msgstr "<дія>"
+
+msgid "action when quoted CR is found"
+msgstr "дія при знаходженні цитованого CR"
+
+msgid "use headers in message's body"
+msgstr "використовувати заголовки в тілі повідомлення"
+
+msgid "reading patches from stdin/tty..."
+msgstr "читання латок з stdin/tty..."
+
+#, c-format
+msgid "empty mbox: '%s'"
+msgstr "порожній mbox: \"%s\""
+
+msgid "git merge-base [-a | --all] <commit> <commit>..."
+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 --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 <посилання> [<коміт>]"
+
+msgid "output all common ancestors"
+msgstr "вивести всіх спільних предків"
+
+msgid "find ancestors for a single n-way merge"
+msgstr "знайти предків для одного n-стороннього злиття"
+
+msgid "list revs not reachable from others"
+msgstr "показати ревізії, недоступні з інших джерел"
+
+msgid "is the first one ancestor of the other?"
+msgstr "чи є перша з них предком другої?"
+
+msgid "find where <commit> forked from reflog of <ref>"
+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 "надсилати результати до стандартного виводу"
+
+msgid "use a diff3 based merge"
+msgstr "використовувати злиття на основі diff3"
+
+msgid "use a zealous diff3 based merge"
+msgstr "використовувати ретельне злиття на основі diff3"
+
+msgid "for conflicts, use our version"
+msgstr "у разі конфліктів використовувати нашу версію"
+
+msgid "for conflicts, use their version"
+msgstr "у разі конфліктів використовувати їхню версію"
+
+msgid "for conflicts, use a union version"
+msgstr "у разі конфліктів використовувати об’єднану версію"
+
+msgid "for conflicts, use this marker size"
+msgstr "у разі конфліктів використовувати цей розмір маркера"
+
+msgid "do not warn about conflicts"
+msgstr "не попереджати про конфлікти"
+
+msgid "set labels for file1/orig-file/file2"
+msgstr "встановити мітки для файл1/оріг-файл/файл2"
+
+#, c-format
+msgid "unknown option %s"
+msgstr "невідома опція %s"
+
+#, c-format
+msgid "could not parse object '%s'"
+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] "неможливо обробити більш ніж %d базу. Ігнорування %s."
+msgstr[1] "неможливо обробити більш ніж %d бази. Ігнорування %s."
+msgstr[2] "неможливо обробити більш ніж %d баз. Ігнорування %s."
+
+msgid "not handling anything other than two heads merge."
+msgstr "не оброблюється нічого, окрім злиття двох верхівок."
+
+#, c-format
+msgid "could not resolve ref '%s'"
+msgstr "не вдалося розвʼязати посилання \"%s\""
+
+#, c-format
+msgid "Merging %s with %s\n"
+msgstr "Злиття %s з %s\n"
+
+msgid "not something we can merge"
+msgstr "не те, що ми в змозі об’єднати"
+
+msgid "refusing to merge unrelated histories"
+msgstr "відмовлено в об’єднанні непов’язаних історій"
+
+msgid "failure to merge"
+msgstr "не вдалося злити"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<опції>] <гілка1> <гілка2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <базове-дерево> <гілка1> <гілка2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "зробити справжнє злиття замість тривіального злиття"
+
+msgid "do a trivial merge only"
+msgstr "зробити лише тривіальне злиття"
+
+msgid "also show informational/conflict messages"
+msgstr "також показувати інформаційні/конфліктні повідомлення"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "вивести назви файлів без режимів/oid/стадій"
+
+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 "--trivial-merge несумісна з усіма іншими опціями"
+
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base несумісна з --stdin"
+
+#, c-format
+msgid "malformed input line: '%s'."
+msgstr "невірно сформований рядок вводу: \"%s\"."
+
+#, c-format
+msgid "merging cannot continue; got unclean result of %d"
+msgstr "неможливо продовжити злиття; отримано брудний результат для %d"
+
+msgid "git merge [<options>] [<commit>...]"
+msgstr "git merge [<опції>] [<коміт>...]"
+
+msgid "switch `m' requires a value"
+msgstr "перемикач \"m\" потребує значення"
+
+#, c-format
+msgid "option `%s' requires a value"
+msgstr "опція \"%s\" потребує значення"
+
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr "Не вдалося знайти стратегію злиття \"%s\".\n"
+
+#, c-format
+msgid "Available strategies are:"
+msgstr "Доступні стратегії:"
+
+#, c-format
+msgid "Available custom strategies are:"
+msgstr "Доступні спеціальні стратегії:"
+
+msgid "do not show a diffstat at the end of the merge"
+msgstr "не показувати diffstat наприкінці злиття"
+
+msgid "show a diffstat at the end of the merge"
+msgstr "показувати diffstat наприкінці злиття"
+
+msgid "(synonym to --stat)"
+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 "створити єдиний коміт замість злиття"
+
+msgid "perform a commit if the merge succeeds (default)"
+msgstr "виконати коміт, якщо злиття пройшло успішно (за замовчуванням)"
+
+msgid "edit message before committing"
+msgstr "редагувати допис перед комітом"
+
+msgid "allow fast-forward (default)"
+msgstr "дозволити перемотування вперед (за замовчуванням)"
+
+msgid "abort if fast-forward is not possible"
+msgstr "перервати, якщо перемотування вперед неможливе"
+
+msgid "verify that the named commit has a valid GPG signature"
+msgstr "перевіряти, чи має коміт дійсний GPG-підпис"
+
+msgid "strategy"
+msgstr "стратегія"
+
+msgid "merge strategy to use"
+msgstr "яку стратегію злиття використовувати"
+
+msgid "option=value"
+msgstr "опція=значення"
+
+msgid "option for selected merge strategy"
+msgstr "опція для обраної стратегії злиття"
+
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr "допис до коміту злиття (для злиття без перемотування вперед)"
+
+msgid "use <name> instead of the real target"
+msgstr "використовувати <назву> замість реальної цілі"
+
+msgid "abort the current in-progress merge"
+msgstr "перервати поточне злиття"
+
+msgid "--abort but leave index and working tree alone"
+msgstr "--abort, але зберегти стан індексу і робочого дерева"
+
+msgid "continue the current in-progress merge"
+msgstr "продовжити поточний процес злиття"
+
+msgid "bypass pre-merge-commit and commit-msg hooks"
+msgstr "обходити pre-merge-commit та commit-msg гачки"
+
+msgid "could not run stash."
+msgstr "не вдалося виконати stash."
+
+msgid "stash failed"
+msgstr "не вдалося додати до схову"
+
+#, c-format
+msgid "not a valid object: %s"
+msgstr "не є припустимим обʼєктом: %s"
+
+msgid "read-tree failed"
+msgstr "read-tree завершився невдало"
+
+msgid "Already up to date. (nothing to squash)"
+msgstr "Вже в актуальному стані. (нічого зчавлювати)"
+
+msgid "Already up to date."
+msgstr "Вже в актуальному стані."
+
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr "Коміт зчавлювання -- HEAD не оновлюється\n"
+
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr "Немає допису до злиття -- HEAD не оновлюється\n"
+
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr "\"%s\" не вказує на коміт"
+
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr "Невірна branch.%s.mergeoptions строка: %s"
+
+msgid "Unable to write index."
+msgstr "Не вдалося записати індекс."
+
+msgid "Not handling anything other than two heads merge."
+msgstr "Не оброблюється нічого, окрім злиття двох верхівок."
+
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "невідомий варіант стратегії: -X%s"
+
+#, c-format
+msgid "unable to write %s"
+msgstr "не вдалося записати %s"
+
+#, c-format
+msgid "Could not read from '%s'"
+msgstr "Не вдалося прочитати з \"%s\""
+
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+msgstr ""
+"Не додано коміт злиття; скористайтесь \"git commit\", щоб завершити злиття.\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 "Порожній допис перерве процес коміту.\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 "Порожній допис до коміту."
+
+#, c-format
+msgid "Wonderful.\n"
+msgstr "Чудово.\n"
+
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr ""
+"Автоматичне злиття не вдалося; виправте конфлікти і потім зробіть коміт "
+"результату.\n"
+
+msgid "No current branch."
+msgstr "Немає поточної гілки."
+
+msgid "No remote for the current branch."
+msgstr "Немає віддаленого призначення для поточної гілки."
+
+msgid "No default upstream defined for the current branch."
+msgstr ""
+"Для поточної гілки не визначено першоджерельне сховище за замовчуванням."
+
+#, c-format
+msgid "No remote-tracking branch for %s from %s"
+msgstr "Немає віддалено відстежуваної гілки для %s з %s"
+
+#, c-format
+msgid "Bad value '%s' in environment '%s'"
+msgstr "Невірне значення \"%s\" в оточенні \"%s\""
+
+#, c-format
+msgid "could not close '%s'"
+msgstr "не вдалося закрити \"%s\""
+
+#, c-format
+msgid "not something we can merge in %s: %s"
+msgstr "не те, що можна злити в %s: %s"
+
+msgid "--abort expects no arguments"
+msgstr "--abort не очікує жодних аргументів"
+
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr "Неможливо перервати злиття (відсутній MERGE_HEAD)."
+
+msgid "--quit expects no arguments"
+msgstr "--quit не очікує жодних аргументів"
+
+msgid "--continue expects no arguments"
+msgstr "--continue не очікує жодних аргументів"
+
+msgid "There is no merge in progress (MERGE_HEAD missing)."
+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 "Ви не завершили висмикування (існує CHERRY_PICK_HEAD)."
+
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr "Не вказано коміт і не встановлено merge.defaultToUpstream."
+
+msgid "Squash commit into empty head not supported yet"
+msgstr "Поки що немає підтримки комітів зчавлювання в порожню верхівку"
+
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr "Коміт без перемотування вперед у порожню верхівку не має сенсу"
+
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - не те, що можна злити"
+
+msgid "Can merge only exactly one commit into empty head"
+msgstr "Можна злити лишень один коміт у порожню верхівку"
+
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr "Оновлення %s..%s\n"
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Ваші локальні зміни у наступних файлах буде замінено злиттям:\n"
+"  %s"
+
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr "Спроба справді тривіального внутрішньо-індексного злиття...\n"
+
+#, c-format
+msgid "Nope.\n"
+msgstr "Ні.\n"
+
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr "Приведення дерева до початкового стану...\n"
+
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr "Спроба стратегії злиття %s...\n"
+
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr "Жодна стратегія злиття не впоралася зі злиттям.\n"
+
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr "Злиття зі стратегією %s не вдалося.\n"
+
+#, c-format
+msgid "Using the %s strategy to prepare resolving by hand.\n"
+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 "попередження: вхідний тег не пройшов fsck: %s"
+
+#, c-format
+msgid "error: tag input does not pass fsck: %s"
+msgstr "помилка: вхідний тег не пройшов fsck: %s"
+
+#, c-format
+msgid "%d (FSCK_IGNORE?) should never trigger this callback"
+msgstr "%d (FSCK_IGNORE?) ніколи не мав спричинити цей зворотній виклик"
+
+#, c-format
+msgid "could not read tagged object '%s'"
+msgstr "не вдалося прочитати тегований об’єкт \"%s\""
+
+#, c-format
+msgid "object '%s' tagged as '%s', but is a '%s' type"
+msgstr "об’єкт \"%s\", позначений як \"%s\", але має тип \"%s\""
+
+msgid "could not read from stdin"
+msgstr "не вдалося прочитати з stdin"
+
+msgid "tag on stdin did not pass our strict fsck check"
+msgstr "тег з stdin не пройшов нашу сувору перевірку fsck"
+
+msgid "tag on stdin did not refer to a valid object"
+msgstr "тег з stdin не посилався на дійсний об’єкт"
+
+msgid "unable to write tag file"
+msgstr "не вдалося записати файл тегів"
+
+msgid "input is NUL terminated"
+msgstr "ввід завершено символом NUL"
+
+msgid "allow missing objects"
+msgstr "дозволяти відсутні об’єкти"
+
+msgid "allow creation of more than one tree"
+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"
+
+msgid "git multi-pack-index [<options>] expire"
+msgstr "git multi-pack-index [<опції>] expire"
+
+msgid "git multi-pack-index [<options>] repack [--batch-size=<size>]"
+msgstr "git multi-pack-index [<опції>] repack [--batch-size=<розмір>]"
+
+msgid "directory"
+msgstr "директорія"
+
+msgid "object directory containing set of packfile and pack-index pairs"
+msgstr "директорія об’єктів, що містить набір packfile та pack-index пар"
+
+msgid "preferred-pack"
+msgstr "preferred-pack"
+
+msgid "pack for reuse when computing a multi-pack bitmap"
+msgstr ""
+"пакунок для повторного використання під час обчислення multi-pack bitmap"
+
+msgid "write multi-pack bitmap"
+msgstr "записати multi-pack bitmap"
+
+msgid "write multi-pack index containing only given indexes"
+msgstr "записати multi-pack індекс, що містить лише задані індекси"
+
+msgid "refs snapshot for selecting bitmap commits"
+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 "Директорія %s в індексі, але без підмодуля?"
+
+msgid "Please stage your changes to .gitmodules or stash them to proceed"
+msgstr ""
+"Будь ласка, додайте змінений .gitmodules до індексу або до схову, щоб "
+"продовжити"
+
+#, c-format
+msgid "%.*s is in index"
+msgstr "%.*s в індексі"
+
+msgid "force move/rename even if target exists"
+msgstr "примусово переміщувати/перейменовувати, навіть якщо ціль існує"
+
+msgid "skip move/rename errors"
+msgstr "пропускати помилки переміщення/перейменування"
+
+#, c-format
+msgid "destination '%s' is not a directory"
+msgstr "місце призначення \"%s\" не є директорією"
+
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr "Перевірка перейменування \"%s\" на \"%s\"\n"
+
+msgid "bad source"
+msgstr "невірне джерело"
+
+msgid "destination exists"
+msgstr "призначення існує"
+
+msgid "can not move directory into itself"
+msgstr "неможливо перемістити директорію в саму себе"
+
+msgid "cannot move directory over file"
+msgstr "неможливо перемістити директорію поверх файлу"
+
+msgid "source directory is empty"
+msgstr "директорія джерела порожня"
+
+msgid "not under version control"
+msgstr "не під контролем версій"
+
+msgid "conflicted"
+msgstr "конфлікт"
+
+#, c-format
+msgid "overwriting '%s'"
+msgstr "перезапис \"%s\""
+
+msgid "Cannot overwrite"
+msgstr "Неможливо перезаписати"
+
+msgid "multiple sources for the same target"
+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"
+
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "Перейменування %s на %s\n"
+
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "перейменування \"%s\" завершилося невдало"
+
+msgid "git name-rev [<options>] <commit>..."
+msgstr "git name-rev [<опції>] <коміт>..."
+
+msgid "git name-rev [<options>] --all"
+msgstr "git name-rev [<опції>] --all"
+
+msgid "git name-rev [<options>] --annotate-stdin"
+msgstr "git name-rev [<опції>] --annotate-stdin"
+
+msgid "print only ref-based names (no object names)"
+msgstr "виводити тільки назви на основі посилань (без назв об’єктів)"
+
+msgid "only use tags to name the commits"
+msgstr "використовувати теги лише для назв комітів"
+
+msgid "only use refs matching <pattern>"
+msgstr "використовувати лише посилання, що збігаються з <шаблоном>"
+
+msgid "ignore refs matching <pattern>"
+msgstr "ігнорувати посилання, що збігаються з <шаблоном>"
+
+msgid "list all commits reachable from all refs"
+msgstr "вивести всі коміти, доступні з усіх посилань"
+
+msgid "deprecated: use --annotate-stdin instead"
+msgstr "застаріле: замість цього використовуйте --annotate-stdin"
+
+msgid "annotate text from stdin"
+msgstr "анотувати текст зі stdin"
+
+msgid "allow to print `undefined` names (default)"
+msgstr "дозволити виводити \"невизначені\" назви (за замовчуванням)"
+
+msgid "dereference tags in the input (internal use)"
+msgstr "розіменувати теги на вході (внутрішнє використання)"
+
+msgid "git notes [--ref <notes-ref>] [list [<object>]]"
+msgstr "git notes [--ref <посилання-нотатки>] [list [<об’єкт>]]"
+
+msgid ""
+"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] [--[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 "git notes [--ref <посилання-нотатки>] edit [--allow-empty] [<об’єкт>]"
+
+msgid "git notes [--ref <notes-ref>] show [<object>]"
+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 "git notes [--ref <посилання-нотатки>] remove [<об’єкт>...]"
+
+msgid "git notes [--ref <notes-ref>] prune [-n] [-v]"
+msgstr "git notes [--ref <посилання-нотатки>] prune [-n] [-v]."
+
+msgid "git notes [--ref <notes-ref>] get-ref"
+msgstr "git notes [--ref <посилання-нотатки>] get-ref"
+
+msgid "git notes [list [<object>]]"
+msgstr "git notes [list [<об’єкт>]]"
+
+msgid "git notes add [<options>] [<object>]"
+msgstr "git notes add [<опції>] [<обʼєкт>]"
+
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr "git notes copy [<опції>] <з-об’єкта> <до-об’єкта"
+
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr "git notes copy --stdin [<з-об’єкта> <до-об’єкта>]..."
+
+msgid "git notes append [<options>] [<object>]"
+msgstr "git notes append [<опції>] [<обʼєкт>]"
+
+msgid "git notes edit [<object>]"
+msgstr "git notes edit [<об’єкт>]"
+
+msgid "git notes show [<object>]"
+msgstr "git notes show [<об’єкт>]"
+
+msgid "git notes merge [<options>] <notes-ref>"
+msgstr "git notes merge [<опції>] <посилання-нотатки>"
+
+msgid "git notes merge --commit [<options>]"
+msgstr "git notes merge --commit [<опції>]"
+
+msgid "git notes merge --abort [<options>]"
+msgstr "git notes merge --abort [<опції>]"
+
+msgid "git notes remove [<object>]"
+msgstr "git notes remove [<об’єкт>]"
+
+msgid "git notes prune [<options>]"
+msgstr "git notes prune [<опції>]"
+
+msgid "Write/edit the notes for the following object:"
+msgstr "Записати/відредагувати нотатки для наступного обʼєкта:"
+
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "не вдалося запустити \"show\" для об’єкта \"%s\""
+
+msgid "could not read 'show' output"
+msgstr "не вдалося прочитати вивід \"show\""
+
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr "не вдалося завершити \"show\" для об’єкта \"%s\""
+
+msgid "please supply the note contents using either -m or -F option"
+msgstr "будь ласка, надайте зміст нотатки, використовуючи опцію -m або -F"
+
+msgid "unable to write note object"
+msgstr "не вдалося записати об’єкт нотатки"
+
+#, c-format
+msgid "the note contents have been left in %s"
+msgstr "вміст нотатки залишено в %s"
+
+#, c-format
+msgid "could not open or read '%s'"
+msgstr "не вдалося відкрити або прочитати \"%s\""
+
+#, c-format
+msgid "failed to resolve '%s' as a valid ref."
+msgstr "не вдалося розпізнати \"%s\" як припустиме посилання."
+
+#, c-format
+msgid "failed to read object '%s'."
+msgstr "не вдалося прочитати обʼєкт \"%s\"."
+
+#, c-format
+msgid "cannot read note data from non-blob object '%s'."
+msgstr "неможливо прочитати дані нотатки з не-blob обʼєкту \"%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/)"
+
+#, c-format
+msgid "no note found for object %s."
+msgstr "для обʼєкта %s не знайдено жодної нотатки."
+
+msgid "note contents as a string"
+msgstr "вміст нотатки як строка"
+
+msgid "note contents in a file"
+msgstr "вміст нотатки у файлі"
+
+msgid "reuse and edit specified note object"
+msgstr "повторно використати та редагувати вказаний обʼєкт нотатки"
+
+msgid "reuse specified note object"
+msgstr "повторно використати вказаний обʼєкт нотатки"
+
+msgid "allow storing empty note"
+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 "Перезапис існуючих нотаток для обʼєкта %s\n"
+
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr "Видалення нотатки для обʼєкта %s\n"
+
+msgid "read objects from stdin"
+msgstr "зчитати обʼєкти з stdin"
+
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+"завантажити перезапис конфігурації для <команда> (мається на увазі --stdin)"
+
+msgid "too few arguments"
+msgstr "замало аргументів"
+
+#, c-format
+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 "нотатки джерельного обʼєкта %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 "не вдалося видалити посилання NOTES_MERGE_PARTIAL"
+
+msgid "failed to delete ref NOTES_MERGE_REF"
+msgstr "не вдалося видалити посилання NOTES_MERGE_REF"
+
+msgid "failed to remove 'git notes merge' worktree"
+msgstr "не вдалося видалити \"git notes merge\" робоче дерево"
+
+msgid "failed to read ref NOTES_MERGE_PARTIAL"
+msgstr "не вдалося прочитати посилання NOTES_MERGE_PARTIAL"
+
+msgid "could not find commit from NOTES_MERGE_PARTIAL."
+msgstr "не вдалося знайти коміт з NOTES_MERGE_PARTIAL."
+
+msgid "could not parse commit from NOTES_MERGE_PARTIAL."
+msgstr "не вдалося розібрати коміт з NOTES_MERGE_PARTIAL."
+
+msgid "failed to resolve NOTES_MERGE_REF"
+msgstr "не вдалося розвʼязати NOTES_MERGE_REF"
+
+msgid "failed to finalize notes merge"
+msgstr "не вдалося завершити злиття нотаток"
+
+#, c-format
+msgid "unknown notes merge strategy %s"
+msgstr "невідома стратегія злиття нотаток %s"
+
+msgid "General options"
+msgstr "Основні опції"
+
+msgid "Merge options"
+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 "Виконнання коміту не злитих нотаток"
+
+msgid "finalize notes merge by committing unmerged notes"
+msgstr "завершити злиття комітом не злитих нотаток"
+
+msgid "Aborting notes merge resolution"
+msgstr "Переривання злиття нотаток"
+
+msgid "abort notes merge"
+msgstr "перервати злиття нотаток"
+
+msgid "cannot mix --commit, --abort or -s/--strategy"
+msgstr "не можна змішувати --commit, --abort або -s/--strategy"
+
+msgid "must specify a notes ref to merge"
+msgstr "необхідно вказати посилання нотаток для злиття"
+
+#, c-format
+msgid "unknown -s/--strategy: %s"
+msgstr "невідома -s/--strategy: %s"
+
+#, c-format
+msgid "a notes merge into %s is already in-progress at %s"
+msgstr "злиття нотаток у %s вже виконується в %s"
+
+#, c-format
+msgid "failed to store link to current notes ref (%s)"
+msgstr "не вдалося зберегти ланку на поточні нотатки посилання (%s)"
+
+#, c-format
+msgid ""
+"Automatic notes merge failed. Fix conflicts in %s and commit the result with "
+"'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."
+msgstr "Не вдалося розвʼязати \"%s\" як припустиме посилання."
+
+#, c-format
+msgid "Object %s has no note\n"
+msgstr "Обʼєкт %s не має нотатки\n"
+
+msgid "attempt to remove non-existent note is not an error"
+msgstr "спроба видалити неіснуючу нотатку не є помилкою"
+
+msgid "read object names from the standard input"
+msgstr "зчитати імена обʼєктів зі стандартного вводу"
+
+msgid "do not remove, show only"
+msgstr "не видаляти, тільки показувати"
+
+msgid "report pruned notes"
+msgstr "звітувати про видалені нотатки"
+
+msgid "notes-ref"
+msgstr "посилання-нотатки"
+
+msgid "use notes from <notes-ref>"
+msgstr "використовувати нотатки з <посилання-нотатки>"
+
+#, c-format
+msgid "unknown subcommand: `%s'"
+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 "невірна CRC запакованого обʼєкта %s"
+
+#, c-format
+msgid "corrupt packed object for %s"
+msgstr "пошкоджений запакований обʼєкт для %s"
+
+#, c-format
+msgid "recursive delta detected for object %s"
+msgstr "виявлено рекурсивну дельту для обʼєкта %s"
+
+#, c-format
+msgid "ordered %u objects, expected %<PRIu32>"
+msgstr "замовлено %u обʼєктів, очікувалось %<PRIu32>"
+
+#, c-format
+msgid "expected object at offset %<PRIuMAX> in pack %s"
+msgstr "очікувався обʼєкт на зміщенні %<PRIuMAX> пакунка %s"
+
+msgid "disabling bitmap writing, packs are split due to pack.packSizeLimit"
+msgstr ""
+"вимкнення bitmap запису, пакунки розбиваються на частини через pack."
+"packSizeLimit"
+
+msgid "Writing objects"
+msgstr "Запис обʼєктів"
+
+#, c-format
+msgid "failed to stat %s"
+msgstr "не вдалося виконати stat %s"
+
+#, c-format
+msgid "failed utime() on %s"
+msgstr "не вдалося виконати utime() на %s"
+
+msgid "failed to write bitmap index"
+msgstr "не вдалося записати bitmap індекс"
+
+#, c-format
+msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
+msgstr "записано %<PRIu32> обʼєкти при очікуванні %<PRIu32>"
+
+msgid "disabling bitmap writing, as some objects are not being packed"
+msgstr "вимкнення bitmap запису, оскільки деякі обʼєкти не упаковуються"
+
+#, c-format
+msgid "delta base offset overflow in pack for %s"
+msgstr "переповнення зміщення дельти бази у пакунку для %s"
+
+#, c-format
+msgid "delta base offset out of bound for %s"
+msgstr "зміщення бази дельти виходить за межі для %s"
+
+msgid "Counting objects"
+msgstr "Підрахунок обʼєктів"
+
+#, c-format
+msgid "unable to get size of %s"
+msgstr "не вдалося отримати розмір %s"
+
+#, c-format
+msgid "unable to parse object header of %s"
+msgstr "не вдалося розібрати заголовок обʼєкта %s"
+
+#, c-format
+msgid "object %s cannot be read"
+msgstr "обʼєкт %s не може бути прочитаний"
+
+#, c-format
+msgid "object %s inconsistent object length (%<PRIuMAX> vs %<PRIuMAX>)"
+msgstr "обʼєкт %s має невідповідну довжину (%<PRIuMAX> проти %<PRIuMAX>)"
+
+msgid "suboptimal pack - out of memory"
+msgstr "неоптимальний пакунок - не вистачає памʼяті"
+
+#, c-format
+msgid "Delta compression using up to %d threads"
+msgstr "Дельта компресія з використанням до %d потоків"
+
+#, c-format
+msgid "unable to pack objects reachable from tag %s"
+msgstr "не вдалося запакувати обʼєкти, доступні з тегу %s"
+
+#, c-format
+msgid "unable to get type of object %s"
+msgstr "не вдалося отримати тип обʼєкта %s"
+
+msgid "Compressing objects"
+msgstr "Компресія обʼєктів"
+
+msgid "inconsistency with delta count"
+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"
+msgstr "не вдалося отримати тип обʼєкта %s у пакунку %s"
+
+#, c-format
+msgid "could not find pack '%s'"
+msgstr "не вдалося знайти пакунок \"%s\""
+
+#, c-format
+msgid "packfile %s cannot be accessed"
+msgstr "неможливо отримати доступ до файлу пакунку %s"
+
+msgid "Enumerating cruft objects"
+msgstr "Перерахування марних обʼєктів"
+
+msgid "unable to add cruft objects"
+msgstr "не вдалося додати марні обʼєкти"
+
+msgid "Traversing cruft objects"
+msgstr "Проходження по марним обʼєктам"
+
+#, c-format
+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 "не вдалося завантажити марний пакунок .mtimes"
+
+msgid "cannot open pack index"
+msgstr "не вдалося відкрити індекс пакунка"
+
+#, c-format
+msgid "loose object at %s could not be examined"
+msgstr "не вдалося розглянути вільний обʼєкт у %s"
+
+msgid "unable to force loose object"
+msgstr "не вдалося примусово вивільнити обʼєкт"
+
+#, c-format
+msgid "not a rev '%s'"
+msgstr "не є ревізією \"%s\""
+
+#, c-format
+msgid "bad revision '%s'"
+msgstr "невірна ревізія \"%s\""
+
+msgid "unable to add recent objects"
+msgstr "не вдалося додати нещодавні обʼєкти"
+
+#, c-format
+msgid "unsupported index version %s"
+msgstr "непідтримувана версія індексу %s"
+
+#, c-format
+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 "<версія>[, <зміщення>]"
+
+msgid "write the pack index file in the specified idx format version"
+msgstr "записати індексний файл пакунка у вказаній версії idx формату"
+
+msgid "maximum size of each output pack file"
+msgstr "максимальний розмір кожного файлу вихідного пакунку"
+
+msgid "ignore borrowed objects from alternate object store"
+msgstr "ігнорувати запозичені обʼєкти з місця збереження запозичених об’єктів"
+
+msgid "ignore packed objects"
+msgstr "ігнорувати запаковані обʼєкти"
+
+msgid "limit pack window by objects"
+msgstr "обмежити вікно пакування за обʼєктами"
+
+msgid "limit pack window by memory in addition to object limit"
+msgstr "обмежити вікно пакування за памʼяттю на додаток до ліміту обʼєкта"
+
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr "максимальна довжина дельта ланцюжка, дозволена в результуючому пакунку"
+
+msgid "reuse existing deltas"
+msgstr "повторно використати існуючі дельти"
+
+msgid "reuse existing objects"
+msgstr "повторно використати існуючі обʼєкти"
+
+msgid "use OFS_DELTA objects"
+msgstr "використати OFS_DELTA обʼєкти"
+
+msgid "use threads when searching for best delta matches"
+msgstr "використовувати потоки під час пошуку найкращих дельта збігів"
+
+msgid "do not create an empty pack output"
+msgstr "не створювати вивід порожнього пакунка"
+
+msgid "read revision arguments from standard input"
+msgstr "зчитувати аргументи ревізії зі стандартного вводу"
+
+msgid "limit the objects to those that are not yet packed"
+msgstr "обмежувати обʼєкти тільки тими, які ще не запаковані"
+
+msgid "include objects reachable from any reference"
+msgstr "включати обʼєкти, досяжні з будь-якого посилання"
+
+msgid "include objects referred by reflog entries"
+msgstr "включати обʼєкти, на які посилаються записи журналу посилань"
+
+msgid "include objects referred to by the index"
+msgstr "включати обʼєкти, на які посилається індекс"
+
+msgid "read packs from stdin"
+msgstr "прочитати пакунки з stdin"
+
+msgid "output pack to stdout"
+msgstr "вивести пакунок у stdout"
+
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+"включати обʼєкти тегів, які посилаються на обʼєкти, що будуть запаковані"
+
+msgid "keep unreachable objects"
+msgstr "зберігати недосяжні обʼєкти"
+
+msgid "pack loose unreachable objects"
+msgstr "запакувати вільні недосяжні обʼєкти"
+
+msgid "unpack unreachable objects newer than <time>"
+msgstr "розпакувати недосяжні обʼєкти, новіші за <час>"
+
+msgid "create a cruft pack"
+msgstr "створити марний пакунок"
+
+msgid "expire cruft objects older than <time>"
+msgstr "видалити марні обʼєкти старіші за <час>"
+
+msgid "use the sparse reachability algorithm"
+msgstr "використовувати алгоритм розрідженої досяжності"
+
+msgid "create thin packs"
+msgstr "створити тонкі пакунки"
+
+msgid "create packs suitable for shallow fetches"
+msgstr "створювати пакунки, придатні для неглибокого отримання"
+
+msgid "ignore packs that have companion .keep file"
+msgstr "ігнорувати пакунки, які мають супровідний .keep файл"
+
+msgid "ignore this pack"
+msgstr "ігнорувати цей пакунок"
+
+msgid "pack compression level"
+msgstr "рівень стиснення пакунка"
+
+msgid "do not hide commits by grafts"
+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 "записати bitmap індекс разом з індексом пакунка"
+
+msgid "write a bitmap index if possible"
+msgstr "записати bitmap індекс, якщо це можливо"
+
+msgid "handling for missing objects"
+msgstr "обробка для відсутніх обʼєктів"
+
+msgid "do not pack objects in promisor packfiles"
+msgstr "не пакувати обʼєкти у promisor пакунки"
+
+msgid "respect islands during delta compression"
+msgstr "поважати острови під час дельта компресії"
+
+msgid "protocol"
+msgstr "протокол"
+
+msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
+msgstr "вилучити всі налаштовані uploadpack.blobpackfileuri з цим протоколом"
+
+#, c-format
+msgid "delta chain depth %d is too deep, forcing %d"
+msgstr "глибина дельта ланцюжка %d занадто глибока, примусове %d"
+
+#, c-format
+msgid "pack.deltaCacheLimit is too high, forcing %d"
+msgstr "pack.deltaCacheLimit занадто великий, примусове %d"
+
+#, c-format
+msgid "bad pack compression level %d"
+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 "мінімальний розмір пакунка - 1 МіБ"
+
+msgid "--thin cannot be used to build an indexable pack"
+msgstr "--thin не можна використовувати для створення індексованого пакунка"
+
+msgid "cannot use --filter without --stdout"
+msgstr "неможливо використовувати --filter без --stdout"
+
+msgid "cannot use --filter with --stdin-packs"
+msgstr "неможливо використовувати --filter з --stdin-packs"
+
+msgid "cannot use internal rev list with --stdin-packs"
+msgstr "неможливо використовувати внутрішній список ревізій з --stdin-packs"
+
+msgid "cannot use internal rev list with --cruft"
+msgstr "неможливо використовувати внутрішній список ревізій з --cruft"
+
+msgid "cannot use --stdin-packs with --cruft"
+msgstr "неможливо використовувати --stdin-packs з --cruft"
+
+msgid "cannot use --max-pack-size with --cruft"
+msgstr "неможливо використовувати --max-pack-size з --cruft"
+
+msgid "Enumerating objects"
+msgstr "Перерахування обʼєктів"
+
+#, c-format
+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"
+"If you still use this command, please add an extra\n"
+"option, '--i-still-use-this', on the command line\n"
+"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 "відмовлено в запуску без --i-still-use-this"
+
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <шаблон>] [--exclude <шаблон>]"
+
+msgid "pack everything"
+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 "git patch-id [--stable | --unstable | --verbatim]"
+
+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 <час>] [--] [<верхівка>...]"
+
+msgid "report pruned objects"
+msgstr "повідомляти про видалені обʼєкти"
+
+msgid "expire objects older than <time>"
+msgstr "видалити обʼєкти старіші за <час>"
+
+msgid "limit traversal to objects outside promisor packfiles"
+msgstr "обмежити обхід об’єктами за межами promisor пакунків"
+
+msgid "cannot prune in a precious-objects repo"
+msgstr "неможливо виконати видалення в precious-objects сховищі"
+
+msgid "git pull [<options>] [<repository> [<refspec>...]]"
+msgstr "git pull [<опції>] [<сховище> [<визначник посилання>...]]"
+
+msgid "control for recursive fetching of submodules"
+msgstr "управління рекурсивним отриманням підмодулів"
+
+msgid "Options related to merging"
+msgstr "Опції, повʼязані зі злиттям"
+
+msgid "incorporate changes by rebasing rather than merging"
+msgstr "вносити зміни через перебазування, а не злиття"
+
+msgid "allow fast-forward"
+msgstr "дозволити перемотування вперед"
+
+msgid "control use of pre-merge-commit and commit-msg hooks"
+msgstr "контролювати використання гачків pre-merge-commit та commit-msg"
+
+msgid "automatically stash/stash pop before and after"
+msgstr "автоматично додавати до та забирати зі схову перед і після"
+
+msgid "Options related to fetching"
+msgstr "Опції, пов’язані з отриманням"
+
+msgid "force overwrite of local branch"
+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 "Серед щойно отриманих посилань немає кандидатів на злиття."
+
+msgid ""
+"Generally this means that you provided a wildcard refspec which had no\n"
+"matches on the remote end."
+msgstr ""
+"Зазвичай це означає, що для визначника посилання, ви ввели символ "
+"підстановки, який не має збігів на віддаленому призначені."
+
+#, c-format
+msgid ""
+"You asked to pull from the remote '%s', but did not specify\n"
+"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 "Будь ласка, вкажіть, з якою гілкою ви хочете виконати злиття."
+
+msgid "See git-pull(1) for details."
+msgstr "Дивіться git-pull(1) для більш детальної інформації."
+
+msgid "<remote>"
+msgstr "<віддалене-призначення>"
+
+msgid "<branch>"
+msgstr "<гілка>"
+
+msgid "There is no tracking information for the current branch."
+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 "ігнорування --verify-signatures для перебазування"
+
+msgid ""
+"You have divergent branches and need to specify how to reconcile them.\n"
+"You can do so by running one of the following commands sometime before\n"
+"your next pull:\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"
+"You can replace \"git config\" with \"git config --global\" to set a "
+"default\n"
+"preference for all repositories. You can also pass --rebase, --no-rebase,\n"
+"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 "Оновлення ненародженої гілки зі змінами, доданими до індексу."
+
+msgid "pull with rebase"
+msgstr "затягнути з перебазуванням"
+
+msgid "Please commit or stash them."
+msgstr "Будь ласка, зробіть коміт або додайте зміни до схову."
+
+#, c-format
+msgid ""
+"fetch updated the current branch head.\n"
+"fast-forwarding your working tree from\n"
+"commit %s."
+msgstr ""
+"отримання оновило верхівку поточної гілки.\n"
+"перемотування вперед вашого робочого дерева з\n"
+"коміту %s."
+
+#, c-format
+msgid ""
+"Cannot fast-forward your working tree.\n"
+"After making sure that you saved anything precious from\n"
+"$ git diff %s\n"
+"output, run\n"
+"$ 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 "Неможливо злити кілька гілок до порожньої верхівки."
+
+msgid "Cannot rebase onto multiple branches."
+msgstr "Неможливо перебазувати на кілька гілок."
+
+msgid "Cannot fast-forward to multiple branches."
+msgstr "Неможливо перемотати вперед кілька гілок."
+
+msgid "Need to specify how to reconcile divergent branches."
+msgstr "Потрібно вказати, як узгоджувати розбіжні гілки."
+
+msgid "cannot rebase with locally recorded submodule modifications"
+msgstr "неможливо перебазувати з локально записаними модифікаціями підмодуля"
+
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git push [<опції>] [<сховище> [<визначник посилання>...]]"
+
+msgid "tag shorthand without <tag>"
+msgstr "скорочення тегу без <тег>"
+
+msgid "--delete only accepts plain target ref names"
+msgstr "--delete приймає лише прості назви посилань"
+
+msgid ""
+"\n"
+"To choose either option permanently, see push.default in 'git help config'.\n"
+msgstr ""
+"\n"
+"Щоб обрати будь-яку з опцій постійною, скористайтесь опцією push.default у "
+"'git help config'.\n"
+
+msgid ""
+"\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 ""
+"\n"
+"Щоб уникнути автоматичного налаштування висхідної гілки, якщо її назва\n"
+"не збігається з назвою локальної гілки, скористайтесь опцією 'simple' для "
+"branch.autoSetupMerge\n"
+"у “git help config”.\n"
+
+#, c-format
+msgid ""
+"The upstream branch of your current branch does not match\n"
+"the name of your current branch.  To push to the upstream branch\n"
+"on the remote, use\n"
+"\n"
+"    git push %s HEAD:%s\n"
+"\n"
+"To push to the branch of the same name on the remote, use\n"
+"\n"
+"    git push %s HEAD\n"
+"%s%s"
+msgstr ""
+"Назва висхідної гілки для вашої поточної гілки не збігається з\n"
+"назвою вашої поточної гілки.  Щоб надіслати до висхідної гілки,\n"
+"скористайтесь командою\n"
+"\n"
+"    git push %s HEAD:%s\n"
+"\n"
+"Щоб надіслати до однойменної гілки на віддаленому сервері скористайтесь\n"
+"\n"
+"    git push %s HEAD\n"
+"%s%s"
+
+#, c-format
+msgid ""
+"You are not currently on a branch.\n"
+"To push the history leading to the current (detached HEAD)\n"
+"state now, use\n"
+"\n"
+"    git push %s HEAD:<name-of-remote-branch>\n"
+msgstr ""
+"Ви зараз не перебуваєте на гілці.\n"
+"Щоб надіслати історію, що веде до поточного (відокремленого HEAD)\n"
+"стану, скористайтесь командою\n"
+"\n"
+"    git push %s HEAD:<назва-віддаленої-гілки>\n"
+
+msgid ""
+"\n"
+"To have this happen automatically for branches without a tracking\n"
+"upstream, see 'push.autoSetupRemote' in 'git help config'.\n"
+msgstr ""
+"\n"
+"Щоб це відбувалося автоматично для невідстежуваних гілок\n"
+"першоджерельного сховища, дивіться 'push.autoSetupRemote' у 'git help "
+"config'.\n"
+
+#, c-format
+msgid ""
+"The current branch %s has no upstream branch.\n"
+"To push the current branch and set the remote as upstream, use\n"
+"\n"
+"    git push --set-upstream %s %s\n"
+"%s"
+msgstr ""
+"Поточна гілка %s не має висхідної гілки.\n"
+"Щоб надіслати поточну гілку і встановити віддалене призначення "
+"першоджерельним сховищем, скористайтесь\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 "Поточна гілка %s має кілька висхідних гілок, відмовлено в надсиланні."
+
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr ""
+"Ви не вказали жодних визначників посилань для надсилання, і push.default "
+"дорівнює \"nothing\"."
+
+#, c-format
+msgid ""
+"You are pushing to remote '%s', which is not the upstream of\n"
+"your current branch '%s', without telling me what to push\n"
+"to update which remote branch."
+msgstr ""
+"Ви надсилаєте до віддаленої гілки \"%s\", яка не є першоджерелом\n"
+"вашої поточної гілки \"%s\", не кажучі мені, що надсилати\n"
+"і яку віддалену гілку оновлювати."
+
+msgid ""
+"Updates were rejected because the tip of your current branch is behind\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"
+"її віддаленого аналога. Якщо ви хочете інтегрувати віддалені зміни,\n"
+"скористайтесь командою \"git pull\" перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
+
+msgid ""
+"Updates were rejected because a pushed branch tip is behind its remote\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"
+"перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
+
+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 ""
+"Оновлення були відхилені, оскільки у віддаленому сховищі міститься робота, "
+"якої\n"
+"немає локально. Зазвичай це стається, коли інше сховище надсилає\n"
+"до того самого посилання. Якщо ви хочете інтегрувати віддалені зміни,\n"
+"скористайтесь командою \"git pull\" перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
+
+msgid "Updates were rejected because the tag already exists in the remote."
+msgstr ""
+"Оновлення були відхилені, оскільки тег вже існує на віддаленому сховищі."
+
+msgid ""
+"You cannot update a remote ref that points at a non-commit object,\n"
+"or update a remote ref to make it point at a non-commit object,\n"
+"without using the '--force' option.\n"
+msgstr ""
+"Ви не можете оновити віддалене посилання, яке вказує на об’єкт, що не є "
+"об’єктом коміту,\n"
+"або оновити віддалене посилання так, щоб воно вказувало на об’єкт, що не є "
+"об’єктом коміту,\n"
+"без використання опції \"--force\".\n"
+
+msgid ""
+"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"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
+
+#, c-format
+msgid "Pushing to %s\n"
+msgstr "Надсилання до %s\n"
+
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr "не вдалося надіслати деякі посилання до '%s'"
+
+msgid ""
+"recursing into submodule with push.recurseSubmodules=only; using on-demand "
+"instead"
+msgstr ""
+"рекурсія в підмодулі з push.recurseSubmodules=only; натомість використовую "
+"on-demand"
+
+#, c-format
+msgid "invalid value for '%s'"
+msgstr "неприпустиме значення для '%s'"
+
+msgid "repository"
+msgstr "сховище"
+
+msgid "push all branches"
+msgstr "надіслати всі гілки"
+
+msgid "mirror all refs"
+msgstr "віддзеркалити всі посилання"
+
+msgid "delete refs"
+msgstr "видалити посилання"
+
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr ""
+"надіслати теги (не можна використовувати з --all, --branches або --mirror)"
+
+msgid "force updates"
+msgstr "оновити примусово"
+
+msgid "<refname>:<expect>"
+msgstr "<refname>:<expect>"
+
+msgid "require old value of ref to be at this value"
+msgstr "вимагати, щоб старе значення посилання було рівним цьому значенню"
+
+msgid "require remote updates to be integrated locally"
+msgstr "вимагати локальної інтеграції віддалених оновлень"
+
+msgid "control recursive pushing of submodules"
+msgstr "контролювати рекурсивне надсилання підмодулів"
+
+msgid "use thin pack"
+msgstr "використовувати тонке пакування"
+
+msgid "receive pack program"
+msgstr "отримати пакетну програму"
+
+msgid "set upstream for git pull/status"
+msgstr "встановити першоджерельне сховище для git pull/status"
+
+msgid "prune locally removed refs"
+msgstr "обрізати локально видалені посилання"
+
+msgid "bypass pre-push hook"
+msgstr "обійти pre-push гачок"
+
+msgid "push missing but relevant tags"
+msgstr "надсилання відсутнє, але є релевантні теги"
+
+msgid "GPG sign the push"
+msgstr "підписати надсилання за допомогою GPG"
+
+msgid "request atomic transaction on remote side"
+msgstr "запросити атомарну транзакцію на віддаленій стороні"
+
+msgid "--delete doesn't make sense without any refs"
+msgstr "--delete не має сенсу без посилань"
+
+#, c-format
+msgid "bad repository '%s'"
+msgstr "невірне сховище \"%s\""
+
+msgid ""
+"No configured push destination.\n"
+"Either specify the URL from the command-line or configure a remote "
+"repository using\n"
+"\n"
+"    git remote add <name> <url>\n"
+"\n"
+"and then push using the remote name\n"
+"\n"
+"    git push <name>\n"
+msgstr ""
+"Немає налаштованого місця призначення надсилання.\n"
+"Або зазначте URL-адресу з командного рядка, або налаштуйте віддалене сховище "
+"за допомогою\n"
+"\n"
+"    git remote add <назва> <адреса>\n"
+"\n"
+"а потім виконайте надсилання, використовуючи назву віддаленого сховища\n"
+"\n"
+"    git push <ім'я>\n"
+
+msgid "--all can't be combined with refspecs"
+msgstr "--all не можна комбінувати з визначниками посилань"
+
+msgid "--mirror can't be combined with refspecs"
+msgstr "--mirror не можна комбінувати з визначниками посилань"
+
+msgid "push options must not have new line characters"
+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 "git range-diff [<опції>] <стара-верхівка>...<нова-верхівка>"
+
+msgid "git range-diff [<options>] <base> <old-tip> <new-tip>"
+msgstr "git range-diff [<опції>] <база> <стара-верхівка> <нова-верхівка>"
+
+msgid "use simple diff colors"
+msgstr "використовувати прості кольори diff"
+
+msgid "notes"
+msgstr "нотатки"
+
+msgid "passed to 'git log'"
+msgstr "передано до \"git log\""
+
+msgid "only emit output related to the first range"
+msgstr "видати тільки вивід, що відноситься до першого діапазону"
+
+msgid "only emit output related to the second range"
+msgstr "видати тільки вивід, що відноситься до другого діапазону"
+
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "не є ревізією: \"%s\""
+
+#, c-format
+msgid "not a commit range: '%s'"
+msgstr "не діапазон комітів: \"%s\""
+
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "не симетричний діапазон: \"%s\""
+
+msgid "need two commit ranges"
+msgstr "потрібно два діапазони комітів"
+
+msgid ""
+"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 ""
+"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 "записати отриманий індекс у <файл>"
+
+msgid "only empty the index"
+msgstr "тільки очистити індекс"
+
+msgid "Merging"
+msgstr "Злиття"
+
+msgid "perform a merge in addition to a read"
+msgstr "виконати злиття на додачу до читання"
+
+msgid "3-way merge if no file level merging required"
+msgstr "3-стороннє злиття, при відсутності потреби в злитті на рівні файлів"
+
+msgid "3-way merge in presence of adds and removes"
+msgstr "3-стороннє злиття за наявності додавання та видалення"
+
+msgid "same as -m, but discard unmerged entries"
+msgstr "те саме, що й -m, але відкидає не злиті записи"
+
+msgid "<subdirectory>/"
+msgstr "<піддиректорія>/"
+
+msgid "read the tree into the index under <subdirectory>/"
+msgstr "зчитати дерево в індекс під <піддиректорію>/"
+
+msgid "update working tree with merge result"
+msgstr "оновити робоче дерево результатом злиття"
+
+msgid "gitignore"
+msgstr "gitignore"
+
+msgid "allow explicitly ignored files to be overwritten"
+msgstr "дозволити перезапис явно проігнорованих файлів"
+
+msgid "don't check the working tree after merging"
+msgstr "не перевіряти робоче дерево після злиття"
+
+msgid "don't update the index or the work tree"
+msgstr "не оновлювати індекс або робоче дерево"
+
+msgid "skip applying sparse checkout filter"
+msgstr "пропустити застосування sparse checkout фільтра"
+
+msgid "debug unpack-trees"
+msgstr "відлагодити unpack-trees"
+
+msgid "suppress feedback messages"
+msgstr "не показувати повідомлення зворотного звʼязку"
+
+msgid "You need to resolve your current index first"
+msgstr "Спочатку вам потрібно розвʼязати поточний індекс"
+
+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'."
+msgstr "не вдалося прочитати \"%s\"."
+
+#, c-format
+msgid "could not create temporary %s"
+msgstr "не вдалося створити тимчасовий %s"
+
+msgid "could not mark as interactive"
+msgstr "не вдалося позначити як інтерактивний"
+
+msgid "could not generate todo list"
+msgstr "не вдалося створити список справ"
+
+msgid "a base commit must be provided with --upstream or --onto"
+msgstr "базовий коміт має бути наданий з --upstream або --onto"
+
+#, c-format
+msgid "%s requires the merge backend"
+msgstr "%s потребує обробника злиття"
+
+#, c-format
+msgid "invalid onto: '%s'"
+msgstr "неприпустимий onto: \"%s\""
+
+#, c-format
+msgid "invalid orig-head: '%s'"
+msgstr "неприпустимий orig-head: \"%s\""
+
+#, c-format
+msgid "ignoring invalid allow_rerere_autoupdate: '%s'"
+msgstr "ігнорування неприпустимого allow_rerere_autoupdate: \"%s\""
+
+#, c-format
+msgid "could not remove '%s'"
+msgstr "не вдалося видалити \"%s\""
+
+msgid ""
+"Resolve all conflicts manually, mark them as resolved with\n"
+"\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n"
+"You can instead skip this commit: run \"git rebase --skip\".\n"
+"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 ""
+"\n"
+"git encountered an error while preparing the patches to replay\n"
+"these revisions:\n"
+"\n"
+"    %s\n"
+"\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 "Невідомий режим перебазування-злиття: %s"
+
+#, c-format
+msgid "could not switch to %s"
+msgstr "не вдалося переключитись на %s"
+
+msgid "apply options and merge options cannot be used together"
+msgstr "apply опції не можна використовувати разом з merge опціями"
+
+#, c-format
+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 ""
+"%s\n"
+"Please specify which branch you want to rebase against.\n"
+"See git-rebase(1) for details.\n"
+"\n"
+"    git rebase '<branch>'\n"
+"\n"
+msgstr ""
+"%s\n"
+"Будь ласка, вкажіть гілку, відносно якої ви хочете виконати перебазування.\n"
+"Дивіться git-rebase(1) для детальної інформації.\n"
+"\n"
+"    git rebase \"<гілка>\"\n"
+"\n"
+"\n"
+
+#, c-format
+msgid ""
+"If you wish to set tracking information for this branch you can do so with:\n"
+"\n"
+"    git branch --set-upstream-to=%s/<branch> %s\n"
+"\n"
+msgstr ""
+"Якщо ви бажаєте налаштувати відстежування для цієї гілки, ви можете зробити "
+"це за допомогою:\n"
+"\n"
+"    git branch --set-upstream-to=%s/<гілка> %s\n"
+"\n"
+
+msgid "exec commands cannot contain newlines"
+msgstr "команди exec не можуть містити символи нового рядка"
+
+msgid "empty exec command"
+msgstr "порожня команда exec"
+
+msgid "rebase onto given branch instead of upstream"
+msgstr "перебазувати на задану гілку замість першоджерельного сховища"
+
+msgid "use the merge-base of upstream and branch as the current base"
+msgstr ""
+"використовувати базу злиття першоджерельного сховища та гілки як поточну базу"
+
+msgid "allow pre-rebase hook to run"
+msgstr "дозволити запуск pre-rebase гачка"
+
+msgid "be quiet. implies --no-stat"
+msgstr "працювати тихесенько. Мається на увазі --no-stat"
+
+msgid "display a diffstat of what changed upstream"
+msgstr "відображати diffstat того, що змінилося у першоджерельному сховищі"
+
+msgid "do not show diffstat of what changed upstream"
+msgstr "не відображати diffstat того, що змінилося у першоджерельному сховищі"
+
+msgid "add a Signed-off-by trailer to each commit"
+msgstr "додати Signed-off-by причіп до кожного коміту"
+
+msgid "make committer date match author date"
+msgstr "зробити так, щоб дата комітера збігалася з датою автора"
+
+msgid "ignore author date and use current date"
+msgstr "ігнорувати дату автора та використати поточну дату"
+
+msgid "synonym of --reset-author-date"
+msgstr "синонім --reset-author-date"
+
+msgid "passed to 'git apply'"
+msgstr "передано в \"git apply\""
+
+msgid "ignore changes in whitespace"
+msgstr "ігнорувати зміни в пробілах"
+
+msgid "cherry-pick all commits, even if unchanged"
+msgstr "висмикнути всі коміти, навіть якщо вони не змінені"
+
+msgid "continue"
+msgstr "продовжити"
+
+msgid "skip current patch and continue"
+msgstr "пропустити поточну латку і продовжити"
+
+msgid "abort and check out the original branch"
+msgstr "перервати і перейти до початкової гілки"
+
+msgid "abort but keep HEAD where it is"
+msgstr "перервати, але залишити HEAD на місці"
+
+msgid "edit the todo list during an interactive rebase"
+msgstr "редагувати список справ під час інтерактивного перебазування"
+
+msgid "show the patch file being applied or merged"
+msgstr "показати файл латки, який застосовується або зливається"
+
+msgid "use apply strategies to rebase"
+msgstr "використовувати стратегії застосування для перебазування"
+
+msgid "use merging strategies to rebase"
+msgstr "використовувати стратегії злиття для перебазування"
+
+msgid "let the user edit the list of commits to rebase"
+msgstr "дозволити користувачеві редагувати список комітів для перебазування"
+
+msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
+msgstr ""
+"(ВИДАЛЕНО) було: спробувати відтворити злиття замість того, щоб ігнорувати їх"
+
+msgid "how to handle commits that become empty"
+msgstr "як обробляти порожні коміти"
+
+msgid "keep commits which start empty"
+msgstr "зберігати коміти, які починаються порожніми"
+
+msgid "move commits that begin with squash!/fixup! under -i"
+msgstr "перемістити коміти, які починаються з squash!/fixup! під -i"
+
+msgid "update branches that point to commits that are being rebased"
+msgstr ""
+"оновити гілки, які вказують на коміти, що знаходяться в стані перебазування"
+
+msgid "add exec lines after each commit of the editable list"
+msgstr "додати exec рядки після кожного коміту редагованого списку"
+
+msgid "allow rebasing commits with empty messages"
+msgstr "дозволити перебазування комітів з порожніми дописами"
+
+msgid "try to rebase merges instead of skipping them"
+msgstr "спробувати перебазувати злиття замість того, щоб пропускати їх"
+
+msgid "use 'merge-base --fork-point' to refine upstream"
+msgstr ""
+"скористайтесь \"merge-base --fork-point\", щоб зазначиити першоджерельне "
+"сховище"
+
+msgid "use the given merge strategy"
+msgstr "використати задану стратегію злиття"
+
+msgid "option"
+msgstr "опція"
+
+msgid "pass the argument through to the merge strategy"
+msgstr "передати аргумент до стратегії злиття"
+
+msgid "rebase all reachable commits up to the root(s)"
+msgstr "перебазувати всі доступні коміти до кореня(ів)."
+
+msgid "automatically re-schedule any `exec` that fails"
+msgstr "автоматично переносити будь-який \"exec\", який завершився невдало"
+
+msgid "apply all changes, even those already present upstream"
+msgstr ""
+"застосовувати всі зміни, навіть ті, що вже існують у першоджерельному сховищі"
+
+msgid "It looks like 'git am' is in progress. Cannot rebase."
+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 "Неможливо прочитати 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 "не вдалося відкинути зміни робочого дерева"
+
+#, c-format
+msgid "could not move back to %s"
+msgstr "не вдалося повернутися до %s"
+
+#, c-format
+msgid ""
+"It seems that there is already a %s directory, and\n"
+"I wonder if you are in the middle of another rebase.  If that is the\n"
+"case, please try\n"
+"\t%s\n"
+"If that is not the case, please\n"
+"\t%s\n"
+"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 "перемикач \"C\" очікує числове значення"
+
+msgid "--strategy requires --merge or --interactive"
+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 "Невідомий обробник перебазування: %s"
+
+msgid "--reschedule-failed-exec requires --exec or --interactive"
+msgstr "--reschedule-failed-exec потребує --exec або --interactive"
+
+#, c-format
+msgid "invalid upstream '%s'"
+msgstr "неприпустиме першоджерельне сховище \"%s\""
+
+msgid "Could not create new root commit"
+msgstr "Не вдалося створити новий кореневий коміт"
+
+#, c-format
+msgid "no such branch/commit '%s'"
+msgstr "немає такої гілки/коміту \"%s\""
+
+#, c-format
+msgid "No such ref: %s"
+msgstr "Немає такого посилання: %s"
+
+msgid "Could not resolve HEAD to a commit"
+msgstr "Не вдалося розвʼязати HEAD у коміт"
+
+#, c-format
+msgid "'%s': need exactly one merge base with branch"
+msgstr "\"%s\": потрібна лишень одна база злиття з гілкою"
+
+#, c-format
+msgid "'%s': need exactly one merge base"
+msgstr "\"%s\": потрібна лишень одна база злиття"
+
+#, c-format
+msgid "Does not point to a valid commit '%s'"
+msgstr "Не вказує на припустимий коміт \"%s\""
+
+msgid "HEAD is up to date."
+msgstr "HEAD знаходиться в актуальному стані."
+
+#, c-format
+msgid "Current branch %s is up to date.\n"
+msgstr "Поточна гілка %s знаходиться в актуальному стані.\n"
+
+msgid "HEAD is up to date, rebase forced."
+msgstr "HEAD знаходиться в актуальному стані, примусове перебазування."
+
+#, c-format
+msgid "Current branch %s is up to date, rebase forced.\n"
+msgstr ""
+"Поточна гілка %s знаходиться в актуальному стані, перебазовуйте примусово.\n"
+
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Гачок pre-rebase відмовився перебазувати."
+
+#, c-format
+msgid "Changes to %s:\n"
+msgstr "Зміни у %s:\n"
+
+#, c-format
+msgid "Changes from %s to %s:\n"
+msgstr "Зміна з %s на %s:\n"
+
+#, c-format
+msgid "First, rewinding head to replay your work on top of it...\n"
+msgstr "Спочатку перемотуємо HEAD, щоб відтворити вашу роботу поверх того...\n"
+
+msgid "Could not detach HEAD"
+msgstr "Не вдалося відʼєднати HEAD"
+
+#, c-format
+msgid "Fast-forwarded %s to %s.\n"
+msgstr "Перемотано вперед %s на %s.\n"
+
+msgid "git receive-pack <git-dir>"
+msgstr "git receive-pack <git-директорія>"
+
+msgid ""
+"By default, updating the current branch in a non-bare repository\n"
+"is denied, because it will make the index and work tree inconsistent\n"
+"with what you pushed, and will require 'git reset --hard' to match\n"
+"the work tree to HEAD.\n"
+"\n"
+"You can set the 'receive.denyCurrentBranch' configuration variable\n"
+"to 'ignore' or 'warn' in the remote repository to allow pushing into\n"
+"its current branch; however, this is not recommended unless you\n"
+"arranged to update its work tree to match what you pushed in some\n"
+"other way.\n"
+"\n"
+"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"
+"\n"
+"You can set 'receive.denyDeleteCurrent' configuration variable to\n"
+"'warn' or 'ignore' in the remote repository to allow deleting the\n"
+"current branch, with or without a warning message.\n"
+"\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 "тихо"
+
+msgid "you must specify a directory"
+msgstr "необхідно вказати директорію"
+
+msgid "git reflog [show] [<log-options>] [<ref>]"
+msgstr "git reflog [show] [<лог-опції>] [<посилання>]"
+
+msgid ""
+"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
+"                  [--rewrite] [--updateref] [--stale-fix]\n"
+"                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
+"<refs>...]"
+msgstr ""
+"git reflog expire [--expire=<час>] [--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 "git reflog exists <посилання>"
+
+#, c-format
+msgid "invalid timestamp '%s' given to '--%s'"
+msgstr "неприпустима позначка часу \"%s\" передана до \"--%s\""
+
+msgid "do not actually prune any entries"
+msgstr "насправді не видаляти жодного запису"
+
+msgid ""
+"rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"
+msgstr "перезаписати старий SHA1 на новий SHA1 запису, який тепер передує йому"
+
+msgid "update the reference to the value of the top reflog entry"
+msgstr "оновити посилання на значення верхнього запису журналу посилань"
+
+msgid "print extra information on screen"
+msgstr "вивести додаткову інформацію на екран"
+
+msgid "timestamp"
+msgstr "позначка часу"
+
+msgid "prune entries older than the specified time"
+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 "обробляти журнали посилань всіх посилань"
+
+msgid "limits processing to reflogs from the current worktree only"
+msgstr "обмежити обробку журналами посилань лише з поточного робочого дерева"
+
+#, c-format
+msgid "Marking reachable objects..."
+msgstr "Позначення досяжних обʼєктів..."
+
+#, c-format
+msgid "%s points nowhere!"
+msgstr "%s вказує в нікуди!"
+
+msgid "no reflog specified to delete"
+msgstr "не вказано журнал посилань для видалення"
+
+#, c-format
+msgid "invalid ref format: %s"
+msgstr "неприпустимий формат посилання: %s"
+
+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 "git remote rename [--[no-]progress] <стара-назва> <нова-назва>"
+
+msgid "git remote remove <name>"
+msgstr "git remote remove <назвa>"
+
+msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"
+msgstr "git remote set-head <назва> (-a | --auto | -d | --delete | <гілка>)"
+
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr "git remote [-v | --verbose] show [-n] <назва>"
+
+msgid "git remote prune [-n | --dry-run] <name>"
+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 "git remote set-branches [--add] <назва> <гілка>..."
+
+msgid "git remote get-url [--push] [--all] <name>"
+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 "git remote set-url --add <назва> <нова-url-адреса>"
+
+msgid "git remote set-url --delete <name> <url>"
+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 "git remote set-branches <назва> <гілка>..."
+
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr "git remote set-branches --add <назва> <гілка>..."
+
+msgid "git remote show [<options>] <name>"
+msgstr "git remote show [<опції>] <назва>"
+
+msgid "git remote prune [<options>] <name>"
+msgstr "git remote prune [<опції>] <назва>"
+
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr "git remote update [<опції>] [<група> | <віддаленe-призначення>]..."
+
+#, c-format
+msgid "Updating %s"
+msgstr "Оновлення %s"
+
+#, c-format
+msgid "Could not fetch %s"
+msgstr "Не вдалося отримати %s"
+
+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 "невідомий аргумент дзеркала: %s"
+
+msgid "fetch the remote branches"
+msgstr "отримати віддалені гілки"
+
+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 "гілка(и) для відстежування"
+
+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 "вказівка головної гілки не має сенсу з --mirror"
+
+msgid "specifying branches to track makes sense only with fetch mirrors"
+msgstr ""
+"вказівка гілок для відстежування має сенс тільки з дзеркалами отримання"
+
+#, c-format
+msgid "remote %s already exists."
+msgstr "віддалений %s вже існує."
+
+#, c-format
+msgid "Could not setup master '%s'"
+msgstr "Не вдалося налаштувати master \"%s\""
+
+#, c-format
+msgid "more than one %s"
+msgstr "більше одного %s"
+
+#, c-format
+msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
+msgstr "unhandled branch.%s.rebase=%s; припускаю \"true\""
+
+#, c-format
+msgid "Could not get fetch map for refspec %s"
+msgstr "Не вдалося забрати карту отримання для визначника посилання %s"
+
+msgid "(matching)"
+msgstr "(збіг)"
+
+msgid "(delete)"
+msgstr "(видалити)"
+
+#, c-format
+msgid "could not set '%s'"
+msgstr "не вдалося встановити \"%s\""
+
+#, c-format
+msgid "could not unset '%s'"
+msgstr "не вдалося скинути \"%s\""
+
+#, c-format
+msgid ""
+"The %s configuration remote.pushDefault in:\n"
+"\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'"
+msgstr "Немає такого віддаленого призначення: \"%s\""
+
+#, c-format
+msgid "Could not rename config section '%s' to '%s'"
+msgstr "Не вдалося перейменувати розділ конфігурації з \"%s\" на \"%s\""
+
+#, c-format
+msgid ""
+"Not updating non-default fetch refspec\n"
+"\t%s\n"
+"\tPlease update the configuration manually if necessary."
+msgstr ""
+"Не оновлюється нестандартний визначник отримання посилань\n"
+"%s\n"
+"Будь ласка, за потреби оновіть конфігурацію вручну."
+
+msgid "Renaming remote references"
+msgstr "Перейменування віддалених посилань"
+
+#, c-format
+msgid "deleting '%s' failed"
+msgstr "не вдалося видалити \"%s\""
+
+#, c-format
+msgid "creating '%s' failed"
+msgstr "не вдалося створити \"%s\""
+
+msgid ""
+"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
+"to delete it, use:"
+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'"
+msgstr "Не вдалося видалити секцію конфігурації \"%s\""
+
+#, c-format
+msgid " new (next fetch will store in remotes/%s)"
+msgstr " нова (наступне отримання зберігатиметься у віддалених remotes/%s)"
+
+msgid " tracked"
+msgstr " відстежується"
+
+msgid " skipped"
+msgstr " пропущена"
+
+msgid " stale (use 'git remote prune' to remove)"
+msgstr " застаріла (скористайтесь \"git remote prune\", щоб видалити)"
+
+msgid " ???"
+msgstr " ???"
+
+#, c-format
+msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
+msgstr "неприпустиме branch.%s.merge; неможливо перебазувати на > 1 гілку"
+
+#, c-format
+msgid "rebases interactively onto remote %s"
+msgstr "перебазувати інтерактивно на віддалене призначення %s"
+
+#, c-format
+msgid "rebases interactively (with merges) onto remote %s"
+msgstr "перебазувати інтерактивно (зі злиттям) на віддалене призначення %s"
+
+#, c-format
+msgid "rebases onto remote %s"
+msgstr "перебазувати на віддалене призначення %s"
+
+#, c-format
+msgid " merges with remote %s"
+msgstr " зливається з віддаленим призначенням %s"
+
+#, c-format
+msgid "merges with remote %s"
+msgstr "зливається з віддаленим призначенням %s"
+
+#, c-format
+msgid "%-*s    and with remote %s\n"
+msgstr "%-*s    та з віддаленим призначенням %s\n"
+
+msgid "create"
+msgstr "створити"
+
+msgid "delete"
+msgstr "видалити"
+
+msgid "up to date"
+msgstr "в актуальному стані"
+
+msgid "fast-forwardable"
+msgstr "з можливістю перемотування вперед"
+
+msgid "local out of date"
+msgstr "локальне сховище застаріло"
+
+#, c-format
+msgid "    %-*s forces to %-*s (%s)"
+msgstr "    %-*s примусово надіслати до %-*s (%s)"
+
+#, c-format
+msgid "    %-*s pushes to %-*s (%s)"
+msgstr "    %-*s надіслати до %-*s (%s)"
+
+#, c-format
+msgid "    %-*s forces to %s"
+msgstr "    %-*s примусово надіслати до %s"
+
+#, c-format
+msgid "    %-*s pushes to %s"
+msgstr "    %-*s надіслати до %s"
+
+msgid "do not query remotes"
+msgstr "не запитувати віддалені призначення"
+
+#, c-format
+msgid "* remote %s"
+msgstr "* віддалене %s"
+
+#, c-format
+msgid "  Fetch URL: %s"
+msgstr "  URL-адреса отримання: %s"
+
+msgid "(no URL)"
+msgstr "(без URL-адреси)"
+
+#. TRANSLATORS: the colon ':' should align
+#. with the one in " Fetch URL: %s"
+#. translation.
+#.
+
+#, c-format
+msgid "  Push  URL: %s"
+msgstr "  URL-адреса надсилання: %s"
+
+#, c-format
+msgid "  HEAD branch: %s"
+msgstr "  HEAD гілка: %s"
+
+msgid "(not queried)"
+msgstr "(не запитувалось)"
+
+msgid "(unknown)"
+msgstr "(невідомо)"
+
+#, c-format
+msgid ""
+"  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
+msgstr ""
+"  HEAD гілка (віддалений HEAD неоднозначний, може бути одним з наступних):\n"
+
+#, c-format
+msgid "  Remote branch:%s"
+msgid_plural "  Remote branches:%s"
+msgstr[0] " Віддалена гілка:%s"
+msgstr[1] " Віддалені гілки:%s"
+msgstr[2] " Віддалених гілок:%s"
+
+msgid " (status not queried)"
+msgstr " (статус не запитувався)"
+
+msgid "  Local branch configured for 'git pull':"
+msgid_plural "  Local branches configured for 'git pull':"
+msgstr[0] "  Локальну гілку налаштовано на \"git pull\":"
+msgstr[1] "  Локальні гілки налаштовано на \"git pull\":"
+msgstr[2] "  Локальних гілок налаштовано на \"git pull\":"
+
+msgid "  Local refs will be mirrored by 'git push'"
+msgstr "  Локальні посилання будуть віддзеркалені за допомогою \"git push\""
+
+#, c-format
+msgid "  Local ref configured for 'git push'%s:"
+msgid_plural "  Local refs configured for 'git push'%s:"
+msgstr[0] "  Локальне посилання налаштовано для \"git push\"%s:"
+msgstr[1] "  Локальних посилання налаштовано для \"git push\"%s:"
+msgstr[2] "  Локальних посилань налаштовано для \"git push\"%s:"
+
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr ""
+"встановити refs/remotes/<назва>/HEAD відповідно до віддаленого призначення"
+
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr "видалити refs/remotes/<назва>/HEAD"
+
+msgid "Cannot determine remote HEAD"
+msgstr "Не вдалося визначити віддалений HEAD"
+
+msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
+msgstr ""
+"Існує кілька віддалених HEAD гілок. Будь ласка, виберіть одну з них, "
+"скориставшись:"
+
+#, c-format
+msgid "Could not delete %s"
+msgstr "Не вдалося видалити %s"
+
+#, c-format
+msgid "Not a valid ref: %s"
+msgstr "Не є припустимим посиланням: %s"
+
+#, c-format
+msgid "Could not setup %s"
+msgstr "Не вдалося налаштувати %s"
+
+#, c-format
+msgid " %s will become dangling!"
+msgstr " %s стануть висячими!"
+
+#, c-format
+msgid " %s has become dangling!"
+msgstr " %s став висячим!"
+
+#, c-format
+msgid "Pruning %s"
+msgstr "Видалення %s"
+
+#, c-format
+msgid "URL: %s"
+msgstr "URL-адреса: %s"
+
+#, c-format
+msgid " * [would prune] %s"
+msgstr " * [буде видалено] %s"
+
+#, c-format
+msgid " * [pruned] %s"
+msgstr " * [видалено] %s"
+
+msgid "prune remotes after fetching"
+msgstr "видалити віддалені призначення після отримання"
+
+#, c-format
+msgid "No such remote '%s'"
+msgstr "Немає такого віддаленого призначення \"%s\""
+
+msgid "add branch"
+msgstr "додати гілку"
+
+msgid "no remote specified"
+msgstr "віддалене призначення не вказано"
+
+msgid "query push URLs rather than fetch URLs"
+msgstr "запитувати URL-адреси надсилань замість URL-адрес отримання"
+
+msgid "return all URLs"
+msgstr "повернути всі URL-адреси"
+
+#, c-format
+msgid "no URLs configured for remote '%s'"
+msgstr "не налаштовано URL-адреси для віддаленого \"%s\""
+
+msgid "manipulate push URLs"
+msgstr "маніпулювати URL-адресами надсилання"
+
+msgid "add URL"
+msgstr "додати URL-адресу"
+
+msgid "delete URLs"
+msgstr "видалити URL-адреси"
+
+msgid "--add --delete doesn't make sense"
+msgstr "--add --delete не має сенсу"
+
+#, c-format
+msgid "Invalid old URL pattern: %s"
+msgstr "Неприпустимий шаблон старої URL-адреси: %s"
+
+#, c-format
+msgid "No such URL found: %s"
+msgstr "Такої URL-адреси не знайдено: %s"
+
+msgid "Will not delete all non-push URLs"
+msgstr "Не видалятиме всі URL-адреси, що не є призначенням надсилань"
+
+msgid "be verbose; must be placed before a subcommand"
+msgstr "розгорнутий вивід; має стояти перед підкомандою"
+
+msgid "git repack [<options>]"
+msgstr "git repack [<опції>]"
+
+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 "не вдалося розпочати 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 "не вдалося завершити pack-objects для перепакування promisor обʼєктів"
+
+#, c-format
+msgid "cannot open index for %s"
+msgstr "неможливо відкрити індекс для %s"
+
+#, c-format
+msgid "pack %s too large to consider in geometric progression"
+msgstr "пакунок %s занадто великий, щоб враховувати в геометричній прогресії"
+
+#, c-format
+msgid "pack %s too large to roll up"
+msgstr "пакунок %s занадто великий для згортання"
+
+#, c-format
+msgid "could not open tempfile %s for writing"
+msgstr "не вдалося відкрити тимчасовий файл %s для запису"
+
+msgid "could not close refs snapshot tempfile"
+msgstr "не вдалося закрити тимчасовий файл знімка посилань"
+
+#, c-format
+msgid "could not remove stale bitmap: %s"
+msgstr "не вдалося видалити застарілий bitmap: %s"
+
+msgid "pack everything in a single pack"
+msgstr "запакувати все в один пакунок"
+
+msgid "same as -a, and turn unreachable objects loose"
+msgstr "те саме, що й -a, та звільняє недосяжні обʼєкти"
+
+msgid "same as -a, pack unreachable cruft objects separately"
+msgstr "те саме, що й -a, пакує недосяжні марні обʼєкти окремо"
+
+msgid "approxidate"
+msgstr "приблизна дата"
+
+msgid "with --cruft, expire objects older than this"
+msgstr "з --cruft видалити обʼєкти, старіші за цей термін"
+
+msgid "remove redundant packs, and run git-prune-packed"
+msgstr "видалити зайві пакунки і запустити git-prune-packed"
+
+msgid "pass --no-reuse-delta to git-pack-objects"
+msgstr "передати --no-reuse-delta до git-pack-objects"
+
+msgid "pass --no-reuse-object to git-pack-objects"
+msgstr "передати --no-reuse-object до git-pack-objects"
+
+msgid "do not run git-update-server-info"
+msgstr "не запускати git-update-server-info"
+
+msgid "pass --local to git-pack-objects"
+msgstr "передати --local до git-pack-objects"
+
+msgid "write bitmap index"
+msgstr "записати bitmap індекс"
+
+msgid "pass --delta-islands to git-pack-objects"
+msgstr "передати --delta-islands до git-pack-objects"
+
+msgid "with -A, do not loosen objects older than this"
+msgstr "з -A, не послабляти обʼєкти, старіші за це значення"
+
+msgid "with -a, repack unreachable objects"
+msgstr "з -a, перепакувати недоступні обʼєкти"
+
+msgid "size of the window used for delta compression"
+msgstr "розмір вікна, що використовується для дельта компресії"
+
+msgid "bytes"
+msgstr "байти"
+
+msgid "same as the above, but limit memory size instead of entries count"
+msgstr ""
+"те саме, що й вище, але обмежує розмір памʼяті замість кількості записів"
+
+msgid "limits the maximum delta depth"
+msgstr "обмежує максимальну глибину дельти"
+
+msgid "limits the maximum number of threads"
+msgstr "обмежує максимальну кількість потоків"
+
+msgid "maximum size of each packfile"
+msgstr "максимальний розмір кожного файла пакунка"
+
+msgid "repack objects in packs marked with .keep"
+msgstr "перепакувати обʼєкти в пакунках, позначених .keep"
+
+msgid "do not repack this pack"
+msgstr "не перепаковувати цей пакунок"
+
+msgid "find a geometric progression with factor <N>"
+msgstr "знайти геометричну прогресію з фактором <Н>"
+
+msgid "write a multi-pack index of the resulting packs"
+msgstr "записати multi-pack-index результуючих пакунків"
+
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "префікс пакунка для зберігання пакунка з обрізаними обʼєктами"
+
+msgid "cannot delete packs in a precious-objects repo"
+msgstr "неможливо видалити пакунки в precious-objects сховищі"
+
+msgid "Nothing new to pack."
+msgstr "Немає нічого нового для пакування."
+
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "префікс пакунку %s не починається з objdir %s"
+
+#, c-format
+msgid "renaming pack to '%s' failed"
+msgstr "перейменування пакунка на \"%s\" завершилося невдало"
+
+#, c-format
+msgid "pack-objects did not write a '%s' file for pack %s-%s"
+msgstr "pack-objects не записав файл \"%s\" для пакунка %s-%s"
+
+#, c-format
+msgid "could not unlink: %s"
+msgstr "не вдалося видалити: %s"
+
+msgid "git replace [-f] <object> <replacement>"
+msgstr "git replace [-f] <обʼєкт> <заміна>"
+
+msgid "git replace [-f] --edit <object>"
+msgstr "git replace [-f] --edit <обʼєкт>"
+
+msgid "git replace [-f] --graft <commit> [<parent>...]"
+msgstr "git replace [-f] --graft <коміт> [<батько>...]"
+
+msgid "git replace -d <object>..."
+msgstr "git replace -d <обʼєкт>..."
+
+msgid "git replace [--format=<format>] [-l [<pattern>]]"
+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 "заміна посилання \"%s\" не знайдена"
+
+#, c-format
+msgid "Deleted replace ref '%s'"
+msgstr "Видалена заміна посилання \"%s\""
+
+#, c-format
+msgid "'%s' is not a valid ref name"
+msgstr "\"%s\" не є припустимою назвою посилання"
+
+#, c-format
+msgid "replace ref '%s' already exists"
+msgstr "заміна посилання \"%s\" вже існує"
+
+#, c-format
+msgid ""
+"Objects must be of the same type.\n"
+"'%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 "cat-file повідомила про збій"
+
+#, c-format
+msgid "unable to open %s for reading"
+msgstr "не вдалося відкрити %s для читання"
+
+msgid "unable to spawn mktree"
+msgstr "не вдалося породити mktree"
+
+msgid "unable to read from mktree"
+msgstr "не вдалося прочитати з mktree"
+
+msgid "mktree reported failure"
+msgstr "mktree повідомила про збій"
+
+msgid "mktree did not return an object name"
+msgstr "mktree не повернув назву обʼєкта"
+
+#, c-format
+msgid "unable to fstat %s"
+msgstr "не вдалося виконати fstat %s"
+
+msgid "unable to write object to database"
+msgstr "не вдалося записати обʼєкт до бази даних"
+
+#, c-format
+msgid "unable to get object type for %s"
+msgstr "не вдалося отримати тип обʼєкта для %s"
+
+msgid "editing object file failed"
+msgstr "редагування файла обʼєкта завершилося невдало"
+
+#, c-format
+msgid "new object is the same as the old one: '%s'"
+msgstr "новий обʼєкт такий самий, як і старий: \"%s\""
+
+#, c-format
+msgid "could not parse %s as a commit"
+msgstr "не вдалося розібрати %s як коміт"
+
+#, c-format
+msgid "bad mergetag in commit '%s'"
+msgstr "невірний mergetag в коміті \"%s\""
+
+#, c-format
+msgid "malformed mergetag in commit '%s'"
+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 "оригінальний коміт \"%s\" має підпис gpg"
+
+msgid "the signature will be removed in the replacement commit!"
+msgstr "підпис буде видалено в коміті заміни!"
+
+#, c-format
+msgid "could not write replacement commit for: '%s'"
+msgstr "не вдалося записати коміт заміни для: \"%s\""
+
+#, c-format
+msgid "graft for '%s' unnecessary"
+msgstr "прищепа для \"%s\" не потрібна"
+
+#, c-format
+msgid "new commit is the same as the old one: '%s'"
+msgstr "новий коміт такий самий, як і старий: \"%s\""
+
+#, c-format
+msgid ""
+"could not convert the following graft(s):\n"
+"%s"
+msgstr ""
+"не вдалося конвертувати наступні прищепи:\n"
+"%s"
+
+msgid "list replace refs"
+msgstr "показати заміни посилань"
+
+msgid "delete replace refs"
+msgstr "видалити заміни посиланнь"
+
+msgid "edit existing object"
+msgstr "редагувати існуючий обʼєкт"
+
+msgid "change a commit's parents"
+msgstr "змінити батьків коміту"
+
+msgid "convert existing graft file"
+msgstr "конвертувати існуючий файл щеплення"
+
+msgid "replace the ref if it exists"
+msgstr "замінити посилання, якщо воно існує"
+
+msgid "do not pretty-print contents for --edit"
+msgstr "не прикрашати вивід вмісту для --edit"
+
+msgid "use this format"
+msgstr "використати цей формат"
+
+msgid "--format cannot be used when not listing"
+msgstr "--format не можна використовувати без list"
+
+msgid "-f only makes sense when writing a replacement"
+msgstr "-f має сенс тільки при записі заміни"
+
+msgid "--raw only makes sense with --edit"
+msgstr "--raw має сенс тільки з --edit"
+
+msgid "-d needs at least one argument"
+msgstr "-d потребує принаймні одного аргументу"
+
+msgid "bad number of arguments"
+msgstr "невірна кількість аргументів"
+
+msgid "-e needs exactly one argument"
+msgstr "-e потребує лишень один аргумент"
+
+msgid "-g needs at least one argument"
+msgstr "-g потребує принаймні одного аргументу"
+
+msgid "--convert-graft-file takes no argument"
+msgstr "--convert-graft-file не потребує аргументів"
+
+msgid "only one pattern can be given with -l"
+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 "зареєструвати чисті вирішення в індексі"
+
+msgid "'git rerere forget' without paths is deprecated"
+msgstr "команда \"git rerere forget\" без шляхів застаріла"
+
+#, c-format
+msgid "unable to generate diff for '%s'"
+msgstr "не вдалося згенерувати diff для \"%s\""
+
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+
+msgid "git reset [-q] [<tree-ish>] [--] <pathspec>..."
+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]] [<деревоподібне-"
+"джерело>]"
+
+msgid "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
+msgstr ""
+"git reset --patch [<деревоподібне-джерело>] [--] [<визначник шляху>...]"
+
+msgid "mixed"
+msgstr "змішане"
+
+msgid "soft"
+msgstr "м’яке"
+
+msgid "hard"
+msgstr "жорстке"
+
+msgid "merge"
+msgstr "злити"
+
+msgid "keep"
+msgstr "зберегти"
+
+msgid "You do not have a valid HEAD."
+msgstr "У вас немає дійсного HEAD."
+
+msgid "Failed to find tree of HEAD."
+msgstr "Не вдалося знайти дерево HEAD."
+
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr "Не вдалося знайти дерево %s."
+
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "HEAD зараз на %s"
+
+#, c-format
+msgid "Cannot do a %s reset in the middle of a merge."
+msgstr "Неможливо виконати %s скидання посеред злиття."
+
+msgid "be quiet, only report errors"
+msgstr "тихесенько, повідомляти лише про помилки"
+
+msgid "skip refreshing the index after reset"
+msgstr "пропустити оновлення індексу після скидання"
+
+msgid "reset HEAD and index"
+msgstr "скинути HEAD та індекс"
+
+msgid "reset only HEAD"
+msgstr "скинути тільки HEAD"
+
+msgid "reset HEAD, index and working tree"
+msgstr "скинути HEAD, індекс та робоче дерево"
+
+msgid "reset HEAD but keep local changes"
+msgstr "скинути HEAD, але зберегти локальні зміни"
+
+msgid "record only the fact that removed paths will be added later"
+msgstr "записати лише той факт, що вилучені шляхи будуть додані пізніше"
+
+#, c-format
+msgid "Failed to resolve '%s' as a valid revision."
+msgstr "Не вдалося розпізнати '%s' як припустиму ревізію."
+
+#, c-format
+msgid "Failed to resolve '%s' as a valid tree."
+msgstr "Не вдалося розпізнати '%s' як припустиме дерево."
+
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr ""
+"використання --mixed зі шляхами застаріло; використовуйте 'git reset -- "
+"<paths>' замість цього."
+
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "Неможливо виконати %s скидання зі шляхами."
+
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr "%s скидання не дозволяється у порожньому сховищі"
+
+msgid "Unstaged changes after reset:"
+msgstr "Неіндексовані зміни після скидання:"
+
+#, c-format
+msgid ""
+"It took %.2f seconds to refresh the index after reset.  You can use\n"
+"'--no-refresh' to avoid this."
+msgstr ""
+"Оновлення індексу після скидання зайняло %.2f секунд.  Ви можете "
+"скористатися параметром\n"
+"'--no-refresh', щоб уникнути цього."
+
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "Не вдалося скинути індексний файл до ревізії '%s'."
+
+msgid "Could not write new index file."
+msgstr "Не вдалося записати новий індексний файл."
+
+#, c-format
+msgid "unable to get disk usage of %s"
+msgstr "не вдалося отримати дані про використання диска %s"
+
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr ""
+"неприпустиме значення для \"%s\": \"%s\", єдиним допустимим форматом є \"%s\""
+
+msgid "rev-list does not support display of notes"
+msgstr "rev-list не підтримує відображення нотаток"
+
+#, c-format
+msgid "marked counting and '%s' cannot be used together"
+msgstr "позначений підрахунок та \"%s\" не можна використовувати разом"
+
+msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
+msgstr "git rev-parse --parseopt [<опції>] -- [<аргументи>...]"
+
+msgid "keep the `--` passed as an arg"
+msgstr "залишити \"--\" переданим як аргумент"
+
+msgid "stop parsing after the first non-option argument"
+msgstr "зупинити розбір після першого неопціонального аргументу"
+
+msgid "output in stuck long form"
+msgstr "виведення в застряглій довгій формі"
+
+msgid "premature end of input"
+msgstr "передчасне закінчення вхідних даних"
+
+msgid "no usage string given before the `--' separator"
+msgstr "не вказана строка використання перед \"--\" розділювачем"
+
+msgid "missing opt-spec before option flags"
+msgstr "відсутній opt-spec перед прапорцями опції"
+
+msgid "Needed a single revision"
+msgstr "Необхідна одна ревізія"
+
+msgid ""
+"git rev-parse --parseopt [<options>] -- [<args>...]\n"
+"   or: git rev-parse --sq-quote [<arg>...]\n"
+"   or: git rev-parse [<options>] [<arg>...]\n"
+"\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 "--resolve-git-dir потребує аргументу"
+
+#, c-format
+msgid "not a gitdir '%s'"
+msgstr "не є git директорією \"%s\""
+
+msgid "--git-path requires an argument"
+msgstr "--git-path потребує аргументу"
+
+msgid "-n requires an argument"
+msgstr "-n потребує аргументу"
+
+msgid "--path-format requires an argument"
+msgstr "--path-format потребує аргументу"
+
+#, c-format
+msgid "unknown argument to --path-format: %s"
+msgstr "невідомий аргумент до --path-format: %s"
+
+msgid "--default requires an argument"
+msgstr "--default потребує аргументу"
+
+msgid "--prefix requires an argument"
+msgstr "--prefix потребує аргументу"
+
+#, c-format
+msgid "unknown mode for --abbrev-ref: %s"
+msgstr "невідомий режим для --abbrev-ref: %s"
+
+msgid "--exclude-hidden cannot be used together with --branches"
+msgstr "--exclude-hidden не можна використовувати разом з --branches"
+
+msgid "--exclude-hidden cannot be used together with --tags"
+msgstr "--exclude-hidden неможливо використовувати разом з --tags"
+
+msgid "--exclude-hidden cannot be used together with --remotes"
+msgstr "--exclude-hidden неможливо використовувати разом з --remotes"
+
+msgid "this operation must be run in a work tree"
+msgstr "цю операцію треба виконувати в робочому дереві"
+
+#, c-format
+msgid "unknown mode for --show-object-format: %s"
+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 "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 "опція \"%s\" очікує число більше нуля"
+
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr "%s: %s неможливо використовувати з %s"
+
+msgid "end revert or cherry-pick sequence"
+msgstr "завершити процес вивертання або висмикування"
+
+msgid "resume revert or cherry-pick sequence"
+msgstr "відновити процес вивертання або висмикування"
+
+msgid "cancel revert or cherry-pick sequence"
+msgstr "скасувати процес вивертання або висмикування"
+
+msgid "skip current commit and continue"
+msgstr "пропустити поточний коміт і продовжити"
+
+msgid "don't automatically commit"
+msgstr "не комітити автоматично"
+
+msgid "edit the commit message"
+msgstr "редагувати допис до коміту"
+
+msgid "parent-number"
+msgstr "номер батька"
+
+msgid "select mainline parent"
+msgstr "вибрати основну батьківську лінію"
+
+msgid "merge strategy"
+msgstr "стратегія злиття"
+
+msgid "option for merge strategy"
+msgstr "опція для стратегії злиття"
+
+msgid "append commit name"
+msgstr "додати назву коміту"
+
+msgid "preserve initially empty commits"
+msgstr "зберігати первинно порожні коміти"
+
+msgid "allow commits with empty messages"
+msgstr "дозволити коміти з порожніми дописами"
+
+msgid "keep redundant, empty commits"
+msgstr "зберігати зайві порожні коміти"
+
+msgid "use the 'reference' format to refer to commits"
+msgstr "використовувати \"reference\" формат для посилань на коміти"
+
+msgid "revert failed"
+msgstr "вивертання не вдалося"
+
+msgid "cherry-pick failed"
+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"
+"file and the HEAD:"
+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] "у наступних файлах є зміни, додані до індексу:"
+
+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:"
+msgstr[0] "наступний файл має локальні зміни:"
+msgstr[1] "наступні файли мають локальні зміни:"
+msgstr[2] "наступних файлів мають локальні зміни:"
+
+msgid "do not list removed files"
+msgstr "не показувати видалені файли"
+
+msgid "only remove from the index"
+msgstr "видалити тільки з індексу"
+
+msgid "override the up-to-date check"
+msgstr "перевизначити перевірку на актуальність"
+
+msgid "allow recursive removal"
+msgstr "дозволити рекурсивне видалення"
+
+msgid "exit with a zero status even if nothing matched"
+msgstr "виходити з нульовим статусом, навіть якщо нічого не збігається"
+
+msgid "No pathspec was given. Which files should I remove?"
+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 "не видалено \"%s\" рекурсивно без -r"
+
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr "git rm: не вдалося видалити %s"
+
+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 ""
+"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 "віддалена назва"
+
+msgid "push all refs"
+msgstr "надіслати всі посилання"
+
+msgid "use stateless RPC protocol"
+msgstr "використовувати протокол RPC без збереження стану"
+
+msgid "read refs from stdin"
+msgstr "прочитати посилання з stdin"
+
+msgid "print status from remote helper"
+msgstr "вивести статус з віддаленого помічника"
+
+msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
+msgstr "git shortlog [<опції>] [<діапазон-ревізій>] [[--] <шлях>...]"
+
+msgid "git log --pretty=short | git shortlog [<options>]"
+msgstr "git log --pretty=short | git shortlog [<опції>]"
+
+msgid "using multiple --group options with stdin is not supported"
+msgstr "використання кількох --group опцій з stdin не підтримується"
+
+#, c-format
+msgid "using %s with stdin is not supported"
+msgstr "використання %s з stdin не підтримується"
+
+#, c-format
+msgid "unknown group type: %s"
+msgstr "невідомий тип групи: %s"
+
+msgid "group by committer rather than author"
+msgstr "групувати за комітером, а не за автором"
+
+msgid "sort output according to the number of commits per author"
+msgstr "сортувати виведення за кількістю комітів на автора"
+
+msgid "suppress commit descriptions, only provides commit count"
+msgstr "приховати описи комітів, показати лише кількість комітів"
+
+msgid "show the email address of each author"
+msgstr "показати адресу електронної пошти кожного автора"
+
+msgid "<w>[,<i1>[,<i2>]]"
+msgstr "<w>[,<i1>[,<i2>]]"
+
+msgid "linewrap output"
+msgstr "обгортати рядки виводу"
+
+msgid "field"
+msgstr "поле"
+
+msgid "group by field"
+msgstr "групувати за полем"
+
+msgid "too many arguments given outside repository"
+msgstr "занадто багато аргументів надано поза сховищем"
+
+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]\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 "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] "ігнорування %s; неможливо обробити більше %d посилання"
+msgstr[1] "ігнорування %s; неможливо обробити більше %d посилань"
+msgstr[2] "ігнорування %s; неможливо обробити більше %d посилань"
+
+#, c-format
+msgid "no matching refs with %s"
+msgstr "немає співпадаючих посилань з %s"
+
+msgid "show remote-tracking and local branches"
+msgstr "показати віддалено відстежувані та локальні гілки"
+
+msgid "show remote-tracking branches"
+msgstr "показати віддалено відстежувані гілки"
+
+msgid "color '*!+-' corresponding to the branch"
+msgstr "колір \"*!+-\" відповідно на гілку"
+
+msgid "show <n> more commits after the common ancestor"
+msgstr "показати ще <н> комітів після спільного предка"
+
+msgid "synonym to more=-1"
+msgstr "синонім до more=-1"
+
+msgid "suppress naming strings"
+msgstr "не показувати назву"
+
+msgid "include the current branch"
+msgstr "включити поточну гілку"
+
+msgid "name commits with their object names"
+msgstr "називати коміти за іменами обʼєктів"
+
+msgid "show possible merge bases"
+msgstr "показати можливі бази злиття"
+
+msgid "show refs unreachable from any other ref"
+msgstr "показати посилання, недосяжні з жодного іншого посилання"
+
+msgid "show commits in topological order"
+msgstr "показати коміти в топологічному порядку"
+
+msgid "show only commits not on the first branch"
+msgstr "показати лише коміти не з найпершої гілки"
+
+msgid "show merges reachable from only one tip"
+msgstr "показати злиття досяжні лише з однієї верхівки"
+
+msgid "topologically sort, maintaining date order where possible"
+msgstr "сортувати топологічно, зберігаючи порядок дат, якщо це можливо"
+
+msgid "<n>[,<base>]"
+msgstr "<н>[,<база>]"
+
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr "показати <н> останніх записів лога посилань, починаючи з бази"
+
+msgid "no branches given, and HEAD is not valid"
+msgstr "не надано гілок, і HEAD не є дійсним"
+
+msgid "--reflog option needs one branch name"
+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] "одночасно може бути показаний лише %d запис."
+msgstr[1] "одночасно можуть бути показані лише %d записи."
+msgstr[2] "одночасно можуть бути показані лише %d записів."
+
+#, c-format
+msgid "no such ref %s"
+msgstr "немає такого посилання %s"
+
+#, c-format
+msgid "cannot handle more than %d rev."
+msgid_plural "cannot handle more than %d revs."
+msgstr[0] "неможливо обробити більше %d ревізії."
+msgstr[1] "неможливо обробити більше %d ревізій."
+msgstr[2] "неможливо обробити більше %d ревізій."
+
+#, c-format
+msgid "'%s' is not a valid ref."
+msgstr "\"%s\" не є припустимим посиланням."
+
+#, c-format
+msgid "cannot find commit %s (%s)"
+msgstr "не вдалося знайти коміт %s (%s)"
+
+msgid "hash-algorithm"
+msgstr "хеш-алгоритм"
+
+msgid "Unknown hash algorithm"
+msgstr "Невідомий хеш-алгоритм"
+
+msgid ""
+"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] [-d | --"
+"dereference]\n"
+"             [-s | --hash[=<н>]] [--abbrev[=<н>]] [--tags]\n"
+"             [--heads] [--] [<шаблон>...]"
+
+msgid "git show-ref --exclude-existing[=<pattern>]"
+msgstr "git show-ref --exclude-existing[=<шаблон>]"
+
+msgid "only show tags (can be combined with heads)"
+msgstr "показати тільки теги (можна комбінувати з верхівками)"
+
+msgid "only show heads (can be combined with tags)"
+msgstr "показати тільки верхівки (можна комбінувати з тегами)"
+
+msgid "stricter reference checking, requires exact ref path"
+msgstr "більш сувора перевірка посилань, потребує точного шляху до посилання"
+
+msgid "show the HEAD reference, even if it would be filtered out"
+msgstr "показати HEAD посилання, навіть якщо воно було б відфільтроване"
+
+msgid "dereference tags into object IDs"
+msgstr "розіменувати теги в ідентифікатори обʼєктів"
+
+msgid "only show SHA1 hash using <n> digits"
+msgstr "показати тільки SHA1 хеш з використанням <н> цифр"
+
+msgid "do not print results to stdout (useful with --verify)"
+msgstr "не виводити результати у stdout (корисно з --verify)"
+
+msgid "show refs from stdin that aren't in local repository"
+msgstr "показати посилання з stdin, яких немає в локальному сховищі"
+
+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 "це робоче дерево не є розрідженим"
+
+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 "не вдалося створити директорію для файлу розрідженого переходу"
+
+msgid "failed to initialize worktree config"
+msgstr "не вдалося ініціалізувати конфігурацію робочого дерева"
+
+msgid "failed to modify sparse-index config"
+msgstr "не вдалося змінити sparse-index конфігурацію"
+
+msgid "initialize the sparse-checkout in cone mode"
+msgstr "ініціалізувати розріджений перехід в режимі конуса"
+
+msgid "toggle the use of a sparse index"
+msgstr "перемкнути використання розрідженого індексу"
+
+#, c-format
+msgid "unable to create leading directories of %s"
+msgstr "не вдалося створити провідні директорії %s"
+
+#, c-format
+msgid "failed to open '%s'"
+msgstr "не вдалося відкрити \"%s\""
+
+#, c-format
+msgid "could not normalize path %s"
+msgstr "не вдалося нормалізувати шлях %s"
+
+#, c-format
+msgid "unable to unquote C-style string '%s'"
+msgstr "неможливо прибрати лапки з C-style строки \"%s\""
+
+msgid "unable to load existing sparse-checkout patterns"
+msgstr "не вдалося завантажити існуючі шаблони розріджених переходів"
+
+msgid "existing sparse-checkout patterns do not use cone mode"
+msgstr "існуючі шаблони розрідженого переходу не використовують режим конуса"
+
+msgid "please run from the toplevel directory in non-cone mode"
+msgstr ""
+"будь ласка, запускайте з директорії верхнього рівня в не конусномі режимі"
+
+msgid "specify directories rather than patterns (no leading slash)"
+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 "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 "читати шаблони зі стандартного вводу"
+
+msgid "no sparse-checkout to add to"
+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 "помилка під час оновлення робочої директорії"
+
+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 "завершити вхідні та вихідні файли символом 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> замість поточних."
+
+msgid "git stash list [<log-options>]"
+msgstr "git stash list [<лог-опції>]"
+
+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 "git stash drop [-q | --quiet] [<схов>]"
+
+msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
+msgstr "git stash pop [--index] [-q | --quiet] [<схов>]"
+
+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 [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] [-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 "git stash create [<допис>]"
+
+#, c-format
+msgid "'%s' is not a stash-like commit"
+msgstr "\"%s\" не є сховоподібним комітом"
+
+#, c-format
+msgid "Too many revisions specified:%s"
+msgstr "Вказано забагато ревізій:%s"
+
+msgid "No stash entries found."
+msgstr "Записи схова не знайдені."
+
+#, c-format
+msgid "%s is not a valid reference"
+msgstr "%s не є припустимим посиланням"
+
+msgid "git stash clear with arguments is unimplemented"
+msgstr "git stash clear з аргументами не реалізовано"
+
+#, c-format
+msgid ""
+"WARNING: Untracked file in way of tracked file!  Renaming\n"
+"            %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 "неможливо застосувати схов посеред злиття"
+
+#, c-format
+msgid "could not generate diff %s^!."
+msgstr "не вдалося згенерувати різницю %s^!."
+
+msgid "conflicts in index. Try without --index."
+msgstr "конфлікти в індексі. Спробуйте без --index."
+
+msgid "could not save index tree"
+msgstr "не вдалося зберегти дерево індекса"
+
+#, c-format
+msgid "Merging %s with %s"
+msgstr "Злиття %s з %s"
+
+msgid "Index was not unstashed."
+msgstr "Індекс не було вилучено зі схову."
+
+msgid "could not restore untracked files from stash"
+msgstr "не вдалося відновити невідстежувані файли зі схову"
+
+msgid "attempt to recreate the index"
+msgstr "спроба відтворити індекс"
+
+#, c-format
+msgid "Dropped %s (%s)"
+msgstr "Скинуто %s (%s)"
+
+#, c-format
+msgid "%s: Could not drop stash entry"
+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 "Запис схову збережено на випадок, якщо він вам знову знадобиться."
+
+msgid "No branch name specified"
+msgstr "Не вказана назва гілки"
+
+msgid "failed to parse tree"
+msgstr "не вдалося розібрати дерево"
+
+msgid "failed to unpack trees"
+msgstr "не вдалося розпакувати дерева"
+
+msgid "include untracked files in the stash"
+msgstr "в тому числі невідстежувані файли схову"
+
+msgid "only show untracked files in the stash"
+msgstr "показувати тільки невідстежувані файли схову"
+
+#, c-format
+msgid "Cannot update %s with %s"
+msgstr "Неможливо оновити %s з %s"
+
+msgid "stash message"
+msgstr "допис до запису схова"
+
+msgid "\"git stash store\" requires one <commit> argument"
+msgstr "\"git stash store\" потребує одного <коміт> аргументу"
+
+msgid "No staged changes"
+msgstr "Немає індексованих змін"
+
+msgid "No changes selected"
+msgstr "Не обрано жодних змін"
+
+msgid "You do not have the initial commit yet"
+msgstr "У вас ще немає початкового коміту"
+
+msgid "Cannot save the current index state"
+msgstr "Неможливо зберегти поточний стан індексу"
+
+msgid "Cannot save the untracked files"
+msgstr "Неможливо зберегти невідстежувані файли"
+
+msgid "Cannot save the current worktree state"
+msgstr "Не вдалося зберегти поточний стан робочого дерева"
+
+msgid "Cannot save the current staged state"
+msgstr "Неможливо зберегти поточний індексований стан"
+
+msgid "Cannot record working tree state"
+msgstr "Неможливо записати стан робочого дерева"
+
+msgid "Can't use --patch and --include-untracked or --all at the same time"
+msgstr ""
+"Не можна використовувати --patch і --include-untracked або --all одночасно"
+
+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 "Ви забули \"git add\"?"
+
+msgid "No local changes to save"
+msgstr "Немає локальних змін для збереження"
+
+msgid "Cannot initialize stash"
+msgstr "Неможливо ініціалізувати схов"
+
+msgid "Cannot save the current status"
+msgstr "Неможливо зберегти поточний стан"
+
+#, c-format
+msgid "Saved working directory and index state %s"
+msgstr "Збережено робочу директорію та стан індексу %s"
+
+msgid "Cannot remove worktree changes"
+msgstr "Неможливо видалити зміни робочого дерева"
+
+msgid "keep index"
+msgstr "зберегти індекс"
+
+msgid "stash staged changes only"
+msgstr "додати до схову тільки індексовані зміни"
+
+msgid "stash in patch mode"
+msgstr "додати до схову у режимі латання"
+
+msgid "quiet mode"
+msgstr "тихий режим"
+
+msgid "include untracked files in stash"
+msgstr "в тому числі невідстежувані файли схову"
+
+msgid "include ignore files"
+msgstr "в тому числи файли ігнорування"
+
+msgid "skip and remove all lines starting with comment character"
+msgstr "пропустити та видалити всі рядки, що починаються з символу коментаря"
+
+msgid "prepend comment character and space to each line"
+msgstr "додати символ коментаря та пробіл до кожного рядка"
+
+#, c-format
+msgid "Expecting a full ref name, got %s"
+msgstr "Очікувалась повна назва посилання, отримано %s"
+
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "не вдалося отримати обʼєкт сховища для підмодуля \"%s\""
+
+#, c-format
+msgid ""
+"could not look up configuration '%s'. Assuming this repository is its own "
+"authoritative upstream."
+msgstr ""
+"не вдалося знайти конфігурацію \"%s\". Мабуть, це сховище має власне "
+"першоджерельне сховище."
+
+#, c-format
+msgid "No url found for submodule path '%s' in .gitmodules"
+msgstr "Не знайдено URL для шляху підмодуля \"%s\" у .gitmodules"
+
+#, c-format
+msgid "Entering '%s'\n"
+msgstr "Введення \"%s\"\n"
+
+#, c-format
+msgid ""
+"run_command returned non-zero status for %s\n"
+"."
+msgstr ""
+"run_command повернула ненульовий статус для %s\n"
+"."
+
+#, c-format
+msgid ""
+"run_command returned non-zero status while recursing in the nested "
+"submodules of %s\n"
+"."
+msgstr ""
+"run_command повернула ненульовий статус під час рекурсії у вкладених "
+"підмодулях %s\n"
+"."
+
+msgid "suppress output of entering each submodule command"
+msgstr "приховати вивід введення кожної команди підмодуля"
+
+msgid "recurse into nested submodules"
+msgstr "рекурсивно у вкладених підмодулях"
+
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <команда>"
+
+#, c-format
+msgid "Failed to register url for submodule path '%s'"
+msgstr "Не вдалося зареєструвати url для підмодуля за шляхом \"%s\""
+
+#, c-format
+msgid "Submodule '%s' (%s) registered for path '%s'\n"
+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'"
+msgstr ""
+"Не вдалося зареєструвати режим оновлення для підмодуля за шляхом \"%s\""
+
+msgid "suppress output for initializing a submodule"
+msgstr "приховати вивід для ініціалізації підмодуля"
+
+msgid "git submodule init [<options>] [<path>]"
+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 "не вдалося розвʼязати HEAD посилання всередині підмодуля \"%s\""
+
+#, c-format
+msgid "failed to recurse into submodule '%s'"
+msgstr "не вдалося обробити рекурсивно підмодуль \"%s\""
+
+msgid "suppress submodule status output"
+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 "git submodule status [--quiet] [--cached] [--recursive] [<шлях>...]"
+
+#, c-format
+msgid "* %s %s(blob)->%s(submodule)"
+msgstr "* %s %s(blob)->%s(підмодуль)"
+
+#, c-format
+msgid "* %s %s(submodule)->%s(blob)"
+msgstr "* %s %s(підмодуль)->%s(blob)"
+
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#, c-format
+msgid "couldn't hash object from '%s'"
+msgstr "не вдалося хешувати обʼєкт з \"%s\""
+
+#, c-format
+msgid "unexpected mode %o\n"
+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 "порівняти коміт в індексі з комітом у HEAD підмодуля"
+
+msgid "skip submodules with 'ignore_config' value set to 'all'"
+msgstr ""
+"пропускати підмодулі зі значенням \"ignore_config\" встановленим у \"all\""
+
+msgid "limit the summary size"
+msgstr "обмежити розмір підсумку"
+
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git summary submodule [<опції>] [<коміт>] [--] [<шлях>]"
+
+msgid "could not fetch a revision for HEAD"
+msgstr "не вдалося отримати ревізію для HEAD"
+
+#, c-format
+msgid "Synchronizing submodule url for '%s'\n"
+msgstr "Синхронізація url підмодуля для \"%s\"\n"
+
+#, c-format
+msgid "failed to register url for submodule path '%s'"
+msgstr "не вдалося зареєструвати url для підмодуля за шляхом \"%s\""
+
+#, c-format
+msgid "failed to update remote for submodule '%s'"
+msgstr "не вдалося оновити віддалене призначення для підмодуля \"%s\""
+
+msgid "suppress output of synchronizing submodule url"
+msgstr "приховати вивід процесу синхронізації url-адреси підмодуля"
+
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+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"
+msgstr "Очищено директорію \"%s\"\n"
+
+#, c-format
+msgid "Could not remove submodule work tree '%s'\n"
+msgstr "Не вдалося видалити робоче дерево підмодуля \"%s\"\n"
+
+#, c-format
+msgid "could not create empty submodule directory %s"
+msgstr "не вдалося створити порожню директорію підмодуля %s"
+
+#, c-format
+msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
+msgstr "Підмодуль \"%s\" (%s) не зареєстровано за шляхом \"%s\"\n"
+
+msgid "remove submodule working trees even if they contain local changes"
+msgstr ""
+"видалити робочі дерева підмодулів, навіть якщо вони містять локальні зміни"
+
+msgid "unregister all submodules"
+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"
+"To allow Git to clone without an alternate in such a case, set\n"
+"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 "не вдалося отримати дескриптор сховища для git директорії \"%s\""
+
+#, c-format
+msgid "submodule '%s' cannot add alternate: %s"
+msgstr "підмодуль \"%s\" не може додати запозичених обʼєкт: %s"
+
+#, c-format
+msgid "Value '%s' for submodule.alternateErrorStrategy is not recognized"
+msgstr "Значення \"%s\" для submodule.alternateErrorStrategy не розпізнано"
+
+#, c-format
+msgid "Value '%s' for submodule.alternateLocation is not recognized"
+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 "не вдалося клонувати \"%s\" у шлях підмодуля \"%s\""
+
+#, c-format
+msgid "directory not empty: '%s'"
+msgstr "директорія не порожня: \"%s\""
+
+#, c-format
+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 "куди буде клоновано новий підмодуль"
+
+msgid "name of the new submodule"
+msgstr "назва нового підмодуля"
+
+msgid "url where to clone the submodule from"
+msgstr "url адреса, звідки клонувати підмодуль"
+
+msgid "depth for shallow clones"
+msgstr "глибина для неглибоких клонів"
+
+msgid "force cloning progress"
+msgstr "примусово звітувати прогрес клонування"
+
+msgid "disallow cloning into non-empty directory"
+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'"
+msgstr ""
+"Неприпустимий режим оновлення \"%s\" налаштовано для підмодуля за шляхом "
+"\"%s\""
+
+#, c-format
+msgid "Submodule path '%s' not initialized"
+msgstr "Підмодуль за шляхом \"%s\" не ініціалізовано"
+
+msgid "Maybe you want to use 'update --init'?"
+msgstr "Можливо, ви хочете скористатись командою \"update --init\"?"
+
+#, c-format
+msgid "Skipping unmerged submodule %s"
+msgstr "Пропуск незлитого підмодуля %s"
+
+#, c-format
+msgid "Skipping submodule '%s'"
+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 "Не вдалося клонувати \"%s\". Запланована повторна спроба"
+
+#, c-format
+msgid "Failed to clone '%s' a second time, aborting"
+msgstr "Не вдалося клонувати \"%s\" вдруге, переривання"
+
+#, c-format
+msgid "Unable to checkout '%s' in submodule path '%s'"
+msgstr "Не вдалося переключитися на \"%s\" у підмодулі за шляхом \"%s\""
+
+#, c-format
+msgid "Unable to rebase '%s' in submodule path '%s'"
+msgstr "Не вдалося перебазувати \"%s\" в підмодулі за шляхом \"%s\""
+
+#, c-format
+msgid "Unable to merge '%s' in submodule path '%s'"
+msgstr "Не вдалося злити \"%s\" в підмодулі за шляхом \"%s\""
+
+#, c-format
+msgid "Execution of '%s %s' failed in submodule path '%s'"
+msgstr "Не вдалося виконати \"%s %s\" у шляху підмодуля \"%s\""
+
+#, c-format
+msgid "Submodule path '%s': checked out '%s'\n"
+msgstr "Шлях підмодуля \"%s\": переключено стан \"%s\"\n"
+
+#, c-format
+msgid "Submodule path '%s': rebased into '%s'\n"
+msgstr "Шлях підмодуля \"%s\": перебазовано в \"%s\"\n"
+
+#, c-format
+msgid "Submodule path '%s': merged in '%s'\n"
+msgstr "Шлях підмодуля \"%s\": злито в \"%s\"\n"
+
+#, c-format
+msgid "Submodule path '%s': '%s %s'\n"
+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'"
+msgstr "не вдалося ініціалізувати підмодуль за шляхом \"%s\""
+
+#, c-format
+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 "Не вдалося знайти поточну ревізію у шляху підмодуля \"%s\""
+
+#, c-format
+msgid "Unable to fetch in submodule path '%s'"
+msgstr "Не вдалося отримати шлях підмодуля \"%s\""
+
+#, c-format
+msgid "Unable to find %s revision in submodule path '%s'"
+msgstr "Не вдалося знайти ревізію %s у шляху підмодуля \"%s\""
+
+#, c-format
+msgid "Failed to recurse into submodule path '%s'"
+msgstr "Не вдалося обробити рекурсивно підмодуль за шляхом \"%s\""
+
+msgid "force checkout updates"
+msgstr "переключитися на оновлення примусово"
+
+msgid "initialize uninitialized submodules before update"
+msgstr "ініціалізувати неініціалізовані підмодулі перед оновленням"
+
+msgid "use SHA-1 of submodule's remote tracking branch"
+msgstr "використовувати SHA-1 гілки віддаленого відстежування підмодуля"
+
+msgid "traverse submodules recursively"
+msgstr "обходити підмодулі рекурсивно"
+
+msgid "don't fetch new objects from the remote site"
+msgstr "не отримувати нові обʼєкти з віддаленої сторони"
+
+msgid "use the 'checkout' update strategy (default)"
+msgstr "використати стратегію оновлення \"checkout \" (за замовчуванням)"
+
+msgid "use the 'merge' update strategy"
+msgstr "використати стратегію оновлення \"merge\""
+
+msgid "use the 'rebase' update strategy"
+msgstr "використати стратегію оновлення \"rebase\""
+
+msgid "create a shallow clone truncated to the specified number of revisions"
+msgstr "створити неглибокий клон, урізаний до вказаної кількості ревізій"
+
+msgid "parallel jobs"
+msgstr "паралельні потоки"
+
+msgid "whether the initial clone should follow the shallow recommendation"
+msgstr "чи повинен початковий клон слідувати неглибоким рекомендаціям"
+
+msgid "don't print cloning progress"
+msgstr "не виводити хід клонування"
+
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "заборонити клонування у непорожній каталог, мається на увазі --init"
+
+msgid ""
+"git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
+"[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
+"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 "приховати вивід при встановленні url підмодуля"
+
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <шлях> <новий-url>"
+
+msgid "set the default tracking branch to master"
+msgstr "встановити гілку відстежування за замовчуванням на master"
+
+msgid "set the default tracking branch"
+msgstr "встановити гілку відстежування за замовчуванням"
+
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <шлях>"
+
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <гілка> <шлях>"
+
+msgid "--branch or --default required"
+msgstr "Потрібно вказати --branch або --default"
+
+msgid "print only error messages"
+msgstr "виводити тільки повідомлення про помилки"
+
+msgid "force creation"
+msgstr "примусове створення"
+
+msgid "show whether the branch would be created"
+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'"
+msgstr "створення гілки \"%s\""
+
+#, c-format
+msgid "Adding existing repo at '%s' to the index\n"
+msgstr "Додавання існуючого сховища за адресою \"%s\" до індексу\n"
+
+#, c-format
+msgid "'%s' already exists and is not a valid git repo"
+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 ""
+"If you want to reuse this local git directory instead of cloning again from\n"
+"  %s\n"
+"use the '--force' option. If the local git directory is not the correct "
+"repo\n"
+"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 "Повторна активація локальної git директорії для підмодуля \"%s\"\n"
+
+#, c-format
+msgid "unable to checkout submodule '%s'"
+msgstr "не вдалося переключитись на підмодуль \"%s\""
+
+msgid "please make sure that the .gitmodules file is in the working tree"
+msgstr ""
+"будь ласка, переконайтеся, що файл .gitmodules знаходиться у робочому дереві"
+
+#, c-format
+msgid "Failed to add submodule '%s'"
+msgstr "Не вдалося додати підмодуль \"%s\""
+
+#, c-format
+msgid "Failed to register submodule '%s'"
+msgstr "Не вдалося зареєструвати підмодуль \"%s\""
+
+#, c-format
+msgid "'%s' already exists in the index"
+msgstr "\"%s\" вже існує в індексі"
+
+#, c-format
+msgid "'%s' already exists in the index and is not a submodule"
+msgstr "\"%s\" вже існує в індексі і не є підмодулем"
+
+#, c-format
+msgid "'%s' does not have a commit checked out"
+msgstr "\"%s\" не має активного коміту"
+
+msgid "branch of repository to add as submodule"
+msgstr "гілка сховища, яку потрібно додати як підмодуль"
+
+msgid "allow adding an otherwise ignored submodule path"
+msgstr "дозволити додавання шляху до підмодуля, який інакше ігнорується"
+
+msgid "borrow the objects from reference repositories"
+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 "URL сховища: \"%s\" має бути абсолютним або починатися з ./|../."
+
+#, c-format
+msgid "'%s' is not a valid submodule name"
+msgstr "\"%s\" не є припустимою назвою підмодуля"
+
+msgid "git submodule--helper <command>"
+msgstr "git submodule--helper <команда>"
+
+msgid "git symbolic-ref [-m <reason>] <name> <ref>"
+msgstr "git symbolic-ref [-m <причина>] <назва> <посилання>"
+
+msgid "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
+msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <назва>"
+
+msgid "git symbolic-ref --delete [-q] <name>"
+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 "скоротити вивід посилань"
+
+msgid "recursively dereference (default)"
+msgstr "рекурсивне розіменування (за замовчуванням)"
+
+msgid "reason"
+msgstr "причина"
+
+msgid "reason of the update"
+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 "git tag -d <назва-тега>..."
+
+msgid ""
+"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 ""
+"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 "git tag -v [--format=<формат>] <назва-тега>..."
+
+#, c-format
+msgid "tag '%s' not found."
+msgstr "тег \"%s\" не знайдено."
+
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr "Видалено тег \"%s\" (було %s)\n"
+
+#, c-format
+msgid ""
+"\n"
+"Write a message for tag:\n"
+"  %s\n"
+"Lines starting with '%c' will be ignored.\n"
+msgstr ""
+"\n"
+"Напишіть допис до тегу:\n"
+"  %s\n"
+"Рядки, що починаються з \"%c\", будуть проігноровані.\n"
+
+#, c-format
+msgid ""
+"\n"
+"Write a message for tag:\n"
+"  %s\n"
+"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 "не вдалося підписати тег"
+
+#, c-format
+msgid ""
+"You have created a nested tag. The object referred to by your new tag is\n"
+"already a tag. If you meant to tag the object that it points to, use:\n"
+"\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 "немає допису до тегу?"
+
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr "Допис до тегу було залишено в %s\n"
+
+msgid "list tag names"
+msgstr "показати назви тегів"
+
+msgid "print <n> lines of each tag message"
+msgstr "вивести <н> рядків кожного допису до тегу"
+
+msgid "delete tags"
+msgstr "видалити теги"
+
+msgid "verify tags"
+msgstr "перевірити теги"
+
+msgid "Tag creation options"
+msgstr "Опції створення тегів"
+
+msgid "annotated tag, needs a message"
+msgstr "анотований тег потребує допису"
+
+msgid "tag message"
+msgstr "допис до тегу"
+
+msgid "force edit of tag message"
+msgstr "примусове редагування допису до тегу"
+
+msgid "annotated and GPG-signed tag"
+msgstr "анотований та підписаний GPG-підписом тег"
+
+msgid "use another key to sign the tag"
+msgstr "використати інший ключ для підпису тегу"
+
+msgid "replace the tag if exists"
+msgstr "замінити тег, якщо він існує"
+
+msgid "create a reflog"
+msgstr "створити журнал посилань"
+
+msgid "Tag listing options"
+msgstr "Опції виводу тегів"
+
+msgid "show tag list in columns"
+msgstr "показати список тегів в стовпчиках"
+
+msgid "print only tags that contain the commit"
+msgstr "вивести тільки теги, що містять коміти"
+
+msgid "print only tags that don't contain the commit"
+msgstr "вивести тільки теги, що не містять комітів"
+
+msgid "print only tags that are merged"
+msgstr "вивести тільки злиті теги"
+
+msgid "print only tags that are not merged"
+msgstr "вивести тільки не злиті теги"
+
+msgid "print only tags of the object"
+msgstr "вивести тільки теги обʼєкта"
+
+#, c-format
+msgid "the '%s' option is only allowed in list mode"
+msgstr "опція \"%s\" дозволена лише в режимі виводу"
+
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr "\"%s\" не є припустимою назвою тега."
+
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "тег \"%s\" вже існує"
+
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr "Неприпустимий режим очищення %s"
+
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+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 "розпаковувач повернув (%d)"
+
+msgid "invalid blob object from stream"
+msgstr "неприпустимий обʼєкт blob з потоку"
+
+msgid "Unpacking objects"
+msgstr "Розпакування обʼєктів"
+
+#, c-format
+msgid "failed to create directory %s"
+msgstr "не вдалося створити директорію %s"
+
+#, c-format
+msgid "failed to delete file %s"
+msgstr "не вдалося видалити файл %s"
+
+#, c-format
+msgid "failed to delete directory %s"
+msgstr "не вдалося видалити директорію %s"
+
+#, c-format
+msgid "Testing mtime in '%s' "
+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 "статистична інформація директорії змінилась після оновлення файла"
+
+msgid "directory stat info changes after adding a file inside subdirectory"
+msgstr ""
+"статистична інформація директорії змінилась після додання файла до "
+"піддиректорії"
+
+msgid "directory stat info does not change after deleting a file"
+msgstr "статистична інформація директорії не змінилась після видалення файла"
+
+msgid "directory stat info does not change after deleting a directory"
+msgstr ""
+"статистична інформація директорії не змінилась після видалення директорії"
+
+msgid " OK"
+msgstr " OK"
+
+msgid "git update-index [<options>] [--] [<file>...]"
+msgstr "git update-index [<опції>] [--] [<файл>...]"
+
+msgid "continue refresh even when index needs update"
+msgstr "продовжити оновлення, навіть якщо індекс потребує змін"
+
+msgid "refresh: ignore submodules"
+msgstr "оновити: ігнорувати підмодулі"
+
+msgid "do not ignore new files"
+msgstr "не ігнорувати нові файли"
+
+msgid "let files replace directories and vice-versa"
+msgstr "дозволити файлам замінювати директорії і навпаки"
+
+msgid "notice files missing from worktree"
+msgstr "повідомляти про файли, відсутні в робочому дереві"
+
+msgid "refresh even if index contains unmerged entries"
+msgstr "оновити, навіть якщо індекс містить не злиті записи"
+
+msgid "refresh stat information"
+msgstr "оновити статистичну інформацію"
+
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr "на кшталт --refresh, але ігнорує assume-unchanged опцію"
+
+msgid "<mode>,<object>,<path>"
+msgstr "<режим>,<обʼєкт>,<шлях>"
+
+msgid "add the specified entry to the index"
+msgstr "додати вказаний запис до індексу"
+
+msgid "mark files as \"not changing\""
+msgstr "позначити файли як \"не змінені\""
+
+msgid "clear assumed-unchanged bit"
+msgstr "очистити assumed-unchanged біт"
+
+msgid "mark files as \"index-only\""
+msgstr "позначити файли як \"тільки для індексу\""
+
+msgid "clear skip-worktree bit"
+msgstr "очистити skip-worktree біт"
+
+msgid "do not touch index-only entries"
+msgstr "ігнорувати файли, призначені тільки для індексу"
+
+msgid "add to index only; do not add content to object database"
+msgstr "додати лише до індексу; не додавати вміст до бази даних обʼєкта"
+
+msgid "remove named paths even if present in worktree"
+msgstr "видалити іменовані шляхи, навіть якщо вони присутні у робочому дереві"
+
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr "з --stdin: вхідні рядки завершуються нульовими байтами"
+
+msgid "read list of paths to be updated from standard input"
+msgstr "прочитати список шляхів для оновлення зі стандартного вводу"
+
+msgid "add entries from standard input to the index"
+msgstr "додати записи зі стандартного вводу до індексу"
+
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr "перезаповнити етапи №2 і №3 для перелічених шляхів"
+
+msgid "only update entries that differ from HEAD"
+msgstr "оновити тільки ті записи, які відрізняються від HEAD"
+
+msgid "ignore files missing from worktree"
+msgstr "ігнорувати файли відсутні в робочому дереві"
+
+msgid "report actions to standard output"
+msgstr "звітувати про дії на стандартний вивід"
+
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr "(для високорівневих команд) забути збережені невирішені конфлікти"
+
+msgid "write index in this format"
+msgstr "записати індекс у цьому форматі"
+
+msgid "enable or disable split index"
+msgstr "увімкнути або вимкнути розщеплений індекс"
+
+msgid "enable/disable untracked cache"
+msgstr "увімкнути/вимкнути невідстежуваний кеш"
+
+msgid "test if the filesystem supports untracked cache"
+msgstr "перевірити, чи підтримує файлова система невідстежуваний кеш"
+
+msgid "enable untracked cache without testing the filesystem"
+msgstr "увімкнути невідстежуваний кеш без тестування файлової системи"
+
+msgid "write out the index even if is not flagged as changed"
+msgstr "записати індекс, навіть якщо він не позначений як змінений"
+
+msgid "enable or disable file system monitor"
+msgstr "увімкнути або вимкнути монітор файлової системи"
+
+msgid "mark files as fsmonitor valid"
+msgstr "позначити файли придатними для fsmonitor"
+
+msgid "clear fsmonitor valid bit"
+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 "Невідстежуваний кеш вимкнено"
+
+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'"
+msgstr "Увімкнено невідстежуваний кеш для \"%s\""
+
+msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
+msgstr ""
+"core.fsmonitor не встановлено; встановіть його, якщо ви дійсно хочете "
+"увімкнути fsmonitor"
+
+msgid "fsmonitor enabled"
+msgstr "fsmonitor увімкнено"
+
+msgid ""
+"core.fsmonitor is set; remove it if you really want to disable fsmonitor"
+msgstr ""
+"core.fsmonitor встановлено; видаліть його, якщо ви дійсно хочете вимкнути "
+"fsmonitor"
+
+msgid "fsmonitor disabled"
+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 "git update-ref [<опції>] --stdin [-z]"
+
+msgid "delete the reference"
+msgstr "видалити посилання"
+
+msgid "update <refname> not the one it points to"
+msgstr "оновити <назвау-посилання>, а не те, на яке воно вказує"
+
+msgid "stdin has NUL-terminated arguments"
+msgstr "stdin має аргументи, що закінчуються NUL"
+
+msgid "read updates from stdin"
+msgstr "читати оновлення з stdin"
+
+msgid "update the info files from scratch"
+msgstr "оновити інформаційні файли з чистого аркуша"
+
+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 "припинити роботу після першого запит/відповідь обміну"
+
+msgid "serve up the info/refs for git-http-backend"
+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 "перервати передачу після <н> секунд неактивності"
+
+msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
+msgstr "git verify-commit [-v | —verbose] [--raw] <коміт>..."
+
+msgid "print commit contents"
+msgstr "показати вміст коміту"
+
+msgid "print raw gpg status output"
+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 "розгорнутий вивід"
+
+msgid "show statistics only"
+msgstr "показати тільки статистику"
+
+msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
+msgstr "git verify-tag [-v | --verbose] [--format=<формат>] [--raw] <тег>..."
+
+msgid "print tag contents"
+msgstr "показати вміст тегу"
+
+msgid ""
+"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
+"                 [--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 "git worktree list [-v | --porcelain [-z]]"
+
+msgid "git worktree lock [--reason <string>] <worktree>"
+msgstr "git worktree lock [--reason <строка>] <робоче дерево>"
+
+msgid "git worktree move <worktree> <new-path>"
+msgstr "git worktree move <робоче-дерево> <новий-шлях>"
+
+msgid "git worktree prune [-n] [-v] [--expire <expire>]"
+msgstr "git worktree prune [-n] [-v] [--expire <термін-дії>]"
+
+msgid "git worktree remove [-f] <worktree>"
+msgstr "git worktree remove [-f] <робоче дерево>"
+
+msgid "git worktree repair [<path>...]"
+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 ""
+"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 "видалити робочі дерева, старіші за <час>"
+
+#, c-format
+msgid "'%s' already exists"
+msgstr "\"%s\" вже існує"
+
+#, c-format
+msgid "unusable worktree destination '%s'"
+msgstr "непридатне місце призначення робочого дерева \"%s\""
+
+#, c-format
+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'"
+msgstr "не вдалося скопіювати конфігурацію робочого дерева з \"%s\" до \"%s\""
+
+#, c-format
+msgid "failed to unset '%s' in '%s'"
+msgstr "не вдалося скинути \"%s\" в \"%s\""
+
+#, c-format
+msgid "could not create directory of '%s'"
+msgstr "не вдалося створити директорію \"%s\""
+
+msgid "initializing"
+msgstr "ініціалізація"
+
+#, c-format
+msgid "Preparing worktree (new branch '%s')"
+msgstr "Підготовка робочого дерева (нова гілка \"%s\")"
+
+#, c-format
+msgid "Preparing worktree (resetting branch '%s'; was at %s)"
+msgstr "Підготовка робочого дерева (скидання гілки \"%s\"; була на %s)"
+
+#, c-format
+msgid "Preparing worktree (checking out '%s')"
+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 "створити нову гілку"
+
+msgid "create or reset a branch"
+msgstr "створити або скинути гілку"
+
+msgid "create unborn/orphaned branch"
+msgstr "створити ненароджену/сирітську гілку"
+
+msgid "populate the new working tree"
+msgstr "заповнити нове робоче дерево"
+
+msgid "keep the new working tree locked"
+msgstr "зберегти нове робоче дерево зафіксованим"
+
+msgid "reason for locking"
+msgstr "причина блокування"
+
+msgid "set up tracking mode (see git-branch(1))"
+msgstr "налаштувати режим відстежування (дивіться git-branch(1))"
+
+msgid "try to match the new branch name with a remote-tracking branch"
+msgstr ""
+"спробуйте співставити нову назву гілки з назвою віддалено відстежуваної гілки"
+
+#, c-format
+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 "додано з --lock"
+
+msgid "--[no-]track can only be used if a new branch is created"
+msgstr "--[no-]track можна використовувати лише при створенні нової гілки"
+
+msgid "show extended annotations and reasons, if available"
+msgstr "показувати розширені анотації та причини, якщо вони доступні"
+
+msgid "add 'prunable' annotation to worktrees older than <time>"
+msgstr "додати анотацію \"prunable\" до робочих дерев, старіших за <час>"
+
+msgid "terminate records with a NUL character"
+msgstr "завершувати записи символом NUL"
+
+#, c-format
+msgid "'%s' is not a working tree"
+msgstr "\"%s\" не є робочим деревом"
+
+msgid "The main working tree cannot be locked or unlocked"
+msgstr "Головне робоче дерево неможливо заблокувати або розблокувати"
+
+#, c-format
+msgid "'%s' is already locked, reason: %s"
+msgstr "\"%s\" вже заблоковано, причина: %s"
+
+#, c-format
+msgid "'%s' is already locked"
+msgstr "\"%s\" вже заблоковано"
+
+#, c-format
+msgid "'%s' is not locked"
+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"
+msgstr "\"%s\" є головним робочим деревом"
+
+#, c-format
+msgid "could not figure out destination name from '%s'"
+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 "валідація завершилася невдало, неможливо перемістити робоче дерево: %s"
+
+#, c-format
+msgid "failed to move '%s' to '%s'"
+msgstr "не вдалося перенести \"%s\" до \"%s\""
+
+#, c-format
+msgid "failed to run 'git status' on '%s'"
+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"
+msgstr "не вдалося виконати \"git status\" на \"%s\", код %d"
+
+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 "валідація завершилася невдало, неможливо видалити робоче дерево: %s"
+
+#, c-format
+msgid "repair: %s: %s"
+msgstr "відремонтувати: %s: %s"
+
+#, c-format
+msgid "error: %s: %s"
+msgstr "помилка: %s: %s"
+
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr "git write-tree [--missing-ok] [--prefix=<префікс>/]"
+
+msgid "<prefix>/"
+msgstr "<префікс>/"
+
+msgid "write tree object for a subdirectory <prefix>"
+msgstr "записати обʼєкт дерева для піддиректорії <префікс>"
+
+msgid "only useful for debugging"
+msgstr "корисно лише для відлагодження"
+
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch не підтримується на цій платформі"
+
+#, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "не вдалося розібрати ключ списку пакунків %s зі значенням \"%s\""
+
+#, c-format
+msgid "bundle list at '%s' has no mode"
+msgstr "список пакунків на \"%s\" не має режиму"
+
+msgid "failed to create temporary file"
+msgstr "не вдалося створити тимчасовий файл"
+
+msgid "insufficient capabilities"
+msgstr "недостатні здібності"
+
+#, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "файл, завантажений з \"%s\", не є пакунком"
+
+msgid "failed to store maximum creation token"
+msgstr "не вдалося зберегти токен максимального створення"
+
+#, c-format
+msgid "unrecognized bundle mode from URI '%s'"
+msgstr "нерозпізнаний режим пакунка з URI \"%s\""
+
+#, c-format
+msgid "exceeded bundle URI recursion limit (%d)"
+msgstr "перевищено ліміт рекурсії URI пакунка (%d)"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "не вдалося завантажити пакунок з URI \"%s\""
+
+#, c-format
+msgid "file at URI '%s' is not a bundle or bundle list"
+msgstr "файл з URI \"%s\" не є пакунком або списком пакунків"
+
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: неочікуваний аргумент: \"%s\""
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: очікувалось flush після аргументів"
+
+msgid "bundle-uri: got an empty line"
+msgstr "bundle-uri: отримано порожній рядок"
+
+msgid "bundle-uri: line is not of the form 'key=value'"
+msgstr "bundle-uri: рядок не відповідає формату \"key=value\""
+
+msgid "bundle-uri: line has empty key or value"
+msgstr "bundle-uri: рядок має порожній ключ або значення"
+
+#, c-format
+msgid "unrecognized bundle hash algorithm: %s"
+msgstr "нерозпізнаний хеш-алгоритм пакунка: %s"
+
+#, c-format
+msgid "unknown capability '%s'"
+msgstr "невідома властивість \"%s\""
+
+#, c-format
+msgid "'%s' does not look like a v2 or v3 bundle file"
+msgstr "\"%s\" не схожий на файл пакунка v2 або v3"
+
+#, c-format
+msgid "unrecognized header: %s%s (%d)"
+msgstr "нерозпізнаний заголовок: %s%s (%d)"
+
+msgid "Repository lacks these prerequisite commits:"
+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:"
+msgstr[0] "Пакунок містить це %<PRIuMAX> посилання:"
+msgstr[1] "Пакунок містить ці %<PRIuMAX> посилання:"
+msgstr[2] "Пакунок містить ці %<PRIuMAX> посилань:"
+
+msgid "The bundle records a complete history."
+msgstr "Пакунок записує повну історію."
+
+#, c-format
+msgid "The bundle requires this ref:"
+msgid_plural "The bundle requires these %<PRIuMAX> refs:"
+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 "не вдалося продублювати дескриптор пакунка"
+
+msgid "Could not spawn pack-objects"
+msgstr "Не вдалося розмножити об’єкти пакунків"
+
+msgid "pack-objects died"
+msgstr "pack-objects завершився невдало"
+
+#, c-format
+msgid "ref '%s' is excluded by the rev-list options"
+msgstr "посилання \"%s\" виключено опціями rev-list"
+
+#, c-format
+msgid "unsupported bundle version %d"
+msgstr "непідтримувана версія пакунка %d"
+
+#, c-format
+msgid "cannot write bundle version %d with algorithm %s"
+msgstr "неможливо записати версію пакунка %d з алгоритмом %s"
+
+msgid "Refusing to create empty bundle."
+msgstr "Відмовлено в створенні порожнього пакунка."
+
+#, c-format
+msgid "cannot create '%s'"
+msgstr "неможливо створити \"%s\""
+
+msgid "index-pack died"
+msgstr "index-pack завершився невдало"
+
+msgid "terminating chunk id appears earlier than expected"
+msgstr "ідентифікатор завершення фрагмента зʼявився раніше, ніж очікувалось"
+
+#, c-format
+msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
+msgstr "невірне зміщення шматка(ів) %<PRIx64> та %<PRIx64>"
+
+#, c-format
+msgid "duplicate chunk ID %<PRIx32> found"
+msgstr "знайдено дубльований шматок з ідентифікатором %<PRIx32>"
+
+#, c-format
+msgid "final chunk has non-zero id %<PRIx32>"
+msgstr "заключний шматок має ненульовий ідентифікатор %<PRIx32>"
+
+msgid "invalid hash version"
+msgstr "неприпустима версія хешу"
+
+#, c-format
+msgid "invalid color value: %.*s"
+msgstr "неприпустиме значення кольору: %.*s"
+
+msgid "Add file contents to the index"
+msgstr "Додати вміст файлу до індексу"
+
+msgid "Apply a series of patches from a mailbox"
+msgstr "Застосувати серію латок з поштової скриньки"
+
+msgid "Annotate file lines with commit information"
+msgstr "Анотувати рядки файлів з інформацією про коміти"
+
+msgid "Apply a patch to files and/or to the index"
+msgstr "Застосувати латку до файлів та/або до індексу"
+
+msgid "Import a GNU Arch repository into Git"
+msgstr "Імпортувати GNU Arch сховище до Git"
+
+msgid "Create an archive of files from a named tree"
+msgstr "Створити архів файлів з названого дерева"
+
+msgid "Use binary search to find the commit that introduced a bug"
+msgstr "Використати бінарний пошук, щоб знайти коміт, який вніс помилку"
+
+msgid "Show what revision and author last modified each line of a file"
+msgstr "Показати, яка ревізія та автор востаннє змінювали кожен рядок файлу"
+
+msgid "List, create, or delete branches"
+msgstr "Показати, створити або видалити гілки"
+
+msgid "Collect information for user to file a bug report"
+msgstr "Зібрати інформацію, щоб користувач міг подати звіт про помилку"
+
+msgid "Move objects and refs by archive"
+msgstr "Перенести архів обʼєктів та посилань"
+
+msgid "Provide content or type and size information for repository objects"
+msgstr "Показати вміст або інформацію про тип і розмір обʼєктів сховища"
+
+msgid "Display gitattributes information"
+msgstr "Відобразити інформацію про gitattributes"
+
+msgid "Debug gitignore / exclude files"
+msgstr "Відлагодити gitignore / вилучити файли"
+
+msgid "Show canonical names and email addresses of contacts"
+msgstr "Показати канонічні імена та адреси електронної пошти контактів"
+
+msgid "Ensures that a reference name is well formed"
+msgstr "Забезпечує правильне формування назви посилання"
+
+msgid "Switch branches or restore working tree files"
+msgstr "Перемкнути гілки або відновити файли робочого дерева"
+
+msgid "Copy files from the index to the working tree"
+msgstr "Скопіювати файли з індексу в робоче дерево"
+
+msgid "Find commits yet to be applied to upstream"
+msgstr "Знайти коміти, які ще не були застосовані до першоджерельного сховища"
+
+msgid "Apply the changes introduced by some existing commits"
+msgstr "Застосувати зміни, внесені деякими існуючими комітами"
+
+msgid "Graphical alternative to git-commit"
+msgstr "Графічна альтернатива git-commit"
+
+msgid "Remove untracked files from the working tree"
+msgstr "Видалити невідстежувані файли з робочого дерева"
+
+msgid "Clone a repository into a new directory"
+msgstr "Клонувати сховище в нову директорію"
+
+msgid "Display data in columns"
+msgstr "Відобразити дані в стовпчиках"
+
+msgid "Record changes to the repository"
+msgstr "Записати зміни у сховище"
+
+msgid "Write and verify Git commit-graph files"
+msgstr "Записати та перевірити файли коміт-графа Git"
+
+msgid "Create a new commit object"
+msgstr "Створити новий обʼєкт коміту"
+
+msgid "Get and set repository or global options"
+msgstr "Отримати та встановити параметри сховища або глобальні параметри"
+
+msgid "Count unpacked number of objects and their disk consumption"
+msgstr "Підрахувати кількість розпакованих обʼєктів та їхнє використання диска"
+
+msgid "Retrieve and store user credentials"
+msgstr "Отримати та зберегти облікові дані користувача"
+
+msgid "Helper to temporarily store passwords in memory"
+msgstr "Помічник для тимчасового зберігання паролів у памʼяті"
+
+msgid "Helper to store credentials on disk"
+msgstr "Помічник для зберігання облікових даних на диску"
+
+msgid "Export a single commit to a CVS checkout"
+msgstr "Експортувати окремий коміт до CVS стану"
+
+msgid "Salvage your data out of another SCM people love to hate"
+msgstr "Врятувати свої дані з іншої SCM, яку всі так неполюбляють"
+
+msgid "A CVS server emulator for Git"
+msgstr "Емулятор CVS сервера для Git"
+
+msgid "A really simple server for Git repositories"
+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 "Згенерувати zip-архів з діагностичною інформацією"
+
+msgid "Show changes between commits, commit and working tree, etc"
+msgstr "Показати зміни між комітами, комітом та робочим деревом, тощо"
+
+msgid "Compares files in the working tree and the index"
+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 "Показати зміни за допомогою звичайних diff засобів"
+
+msgid "Git data exporter"
+msgstr "Експортер даних Git"
+
+msgid "Backend for fast Git data importers"
+msgstr "Обробник для швидких імпортерів даних Git"
+
+msgid "Download objects and refs from another repository"
+msgstr "Завантажити обʼєкти та посилання з іншого сховища"
+
+msgid "Receive missing objects from another repository"
+msgstr "Отримати відсутні обʼєкти з іншого сховища"
+
+msgid "Rewrite branches"
+msgstr "Перезаписати гілки"
+
+msgid "Produce a merge commit message"
+msgstr "Створити допис до коміту злиття"
+
+msgid "Output information on each ref"
+msgstr "Вивести інформацію про кожне посилання"
+
+msgid "Run a Git command on a list of repositories"
+msgstr "Запустити команду Git на списку сховищ"
+
+msgid "Prepare patches for e-mail submission"
+msgstr "Підготувати латки для надсилання електронною поштою"
+
+msgid "Verifies the connectivity and validity of the objects in the database"
+msgstr "Перевіряє звʼязність та валідність обʼєктів у базі даних"
+
+msgid "Cleanup unnecessary files and optimize the local repository"
+msgstr "Видалити непотрібні файли та оптимізувати локальне сховище"
+
+msgid "Extract commit ID from an archive created using git-archive"
+msgstr ""
+"Витягти ідентифікатор коміту з архіву, створеного за допомогою git-archive"
+
+msgid "Print lines matching a pattern"
+msgstr "Вивести рядки, що відповідають шаблону"
+
+msgid "A portable graphical interface to Git"
+msgstr "Портативний графічний інтерфейс до Git"
+
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "Обчислити ідентифікатор обʼєкта та за бажанням створити обʼєкт з файлу"
+
+msgid "Display help information about Git"
+msgstr "Відобразити довідкову інформацію про Git"
+
+msgid "Run git hooks"
+msgstr "Запустити git гачки"
+
+msgid "Server side implementation of Git over HTTP"
+msgstr "Серверна реалізація Git через HTTP"
+
+msgid "Download from a remote Git repository via HTTP"
+msgstr "Завантажити з віддаленого Git сховища через HTTP"
+
+msgid "Push objects over HTTP/DAV to another repository"
+msgstr "Надіслати обʼєкти через HTTP/DAV до іншого сховища"
+
+msgid "Send a collection of patches from stdin to an IMAP folder"
+msgstr "Надіслати збірку латок з stdin до теки IMAP"
+
+msgid "Build pack index file for an existing packed archive"
+msgstr "Побудувати індексний файл пакунка для існуючого запакованого архіву"
+
+msgid "Create an empty Git repository or reinitialize an existing one"
+msgstr "Створити порожнє Git сховище або переініціалізувати існуюче"
+
+msgid "Instantly browse your working repository in gitweb"
+msgstr "Миттєво переглянути своє робоче сховище в gitweb"
+
+msgid "Add or parse structured information in commit messages"
+msgstr "Додати або розібрати структуровану інформацію в дописах до комітів"
+
+msgid "Show commit logs"
+msgstr "Показати журнал коміту"
+
+msgid "Show information about files in the index and the working tree"
+msgstr "Показати інформацію про файли в індексі та робочому дереві"
+
+msgid "List references in a remote repository"
+msgstr "Показати посилання у віддаленому сховищі"
+
+msgid "List the contents of a tree object"
+msgstr "Показати вміст обʼєкта дерева"
+
+msgid "Extracts patch and authorship from a single e-mail message"
+msgstr "Витягує латку та авторство з одного повідомлення електронної пошти"
+
+msgid "Simple UNIX mbox splitter program"
+msgstr "Проста програма-розщеплювач UNIX mbox"
+
+msgid "Run tasks to optimize Git repository data"
+msgstr "Запустити завдання для оптимізації даних Git сховища"
+
+msgid "Join two or more development histories together"
+msgstr "Обʼєднати дві або більше історій розробки"
+
+msgid "Find as good common ancestors as possible for a merge"
+msgstr "Знайти якомога кращого спільного предка для злиття"
+
+msgid "Run a three-way file merge"
+msgstr "Запустити тристороннє злиття файлів"
+
+msgid "Run a merge for files needing merging"
+msgstr "Запустити злиття для файлів, які потрібно обʼєднати"
+
+msgid "The standard helper program to use with git-merge-index"
+msgstr "Стандартна допоміжна програма для використання з git-merge-index"
+
+msgid "Perform merge without touching index or working tree"
+msgstr "Виконати злиття, не торкаючись індексу або робочого дерева"
+
+msgid "Run merge conflict resolution tools to resolve merge conflicts"
+msgstr ""
+"Запустити інструменти вирішення конфліктів, щоб вирішити конфлікти злиття"
+
+msgid "Creates a tag object with extra validation"
+msgstr "Створює обʼєкт тегу з додатковою перевіркою"
+
+msgid "Build a tree-object from ls-tree formatted text"
+msgstr "Побудувати обʼєкт дерева з ls-tree форматованого тексту"
+
+msgid "Write and verify multi-pack-indexes"
+msgstr "Записати і перевірити multi-pack-indexes"
+
+msgid "Move or rename a file, a directory, or a symlink"
+msgstr "Перемістити або перейменувати файл, директорію або символьне посилання"
+
+msgid "Find symbolic names for given revs"
+msgstr "Знайти символьни назви для заданих ревізій"
+
+msgid "Add or inspect object notes"
+msgstr "Додати або перевірити нотатки до обʼєктів"
+
+msgid "Import from and submit to Perforce repositories"
+msgstr "Імпортувати з та надсилати до Perforce сховищ"
+
+msgid "Create a packed archive of objects"
+msgstr "Створити запакований архів обʼєктів"
+
+msgid "Find redundant pack files"
+msgstr "Знайти зайві файли пакунків"
+
+msgid "Pack heads and tags for efficient repository access"
+msgstr "Запакувати верхівки та теги для ефективного доступу до сховища"
+
+msgid "Compute unique ID for a patch"
+msgstr "Обчислити унікальний ідентифікатор для патчу"
+
+msgid "Prune all unreachable objects from the object database"
+msgstr "Видалити всі недосяжні обʼєкти з бази даних обʼєктів"
+
+msgid "Remove extra objects that are already in pack files"
+msgstr "Видалити зайві обʼєкти, які вже є у файлах пакунків"
+
+msgid "Fetch from and integrate with another repository or a local branch"
+msgstr "Отримати та інтегрувати з іншим сховищем або локальною гілкою"
+
+msgid "Update remote refs along with associated objects"
+msgstr "Оновити віддалені посилання разом з асоційованими обʼєктами"
+
+msgid "Applies a quilt patchset onto the current branch"
+msgstr "Застосовує набір латок до поточної гілки"
+
+msgid "Compare two commit ranges (e.g. two versions of a branch)"
+msgstr "Порівняти два діапазони комітів (наприклад, дві версії гілки)"
+
+msgid "Reads tree information into the index"
+msgstr "Зчитує інформацію про дерево в індекс"
+
+msgid "Reapply commits on top of another base tip"
+msgstr "Застосувати коміти поверх іншої верхівки бази"
+
+msgid "Receive what is pushed into the repository"
+msgstr "Отримати те, що надсилається до сховища"
+
+msgid "Manage reflog information"
+msgstr "Керування інформацією журналу посилань"
+
+msgid "Manage set of tracked repositories"
+msgstr "Керувати набором відстежуваних сховищ"
+
+msgid "Pack unpacked objects in a repository"
+msgstr "Запакувати розпаковані обʼєкти у сховищі"
+
+msgid "Create, list, delete refs to replace objects"
+msgstr "Створити, показати, видалити посилання для об’єктів заміни"
+
+msgid "Generates a summary of pending changes"
+msgstr "Створює підсумок змін для розгляду"
+
+msgid "Reuse recorded resolution of conflicted merges"
+msgstr "Використати повторно записане розв’язання конфліктних злиттів"
+
+msgid "Reset current HEAD to the specified state"
+msgstr "Скинути поточний HEAD до вказаного стану"
+
+msgid "Restore working tree files"
+msgstr "Відновити файли робочого дерева"
+
+msgid "Lists commit objects in reverse chronological order"
+msgstr "Показувати обʼєкти коміту у зворотному хронологічному порядку"
+
+msgid "Pick out and massage parameters"
+msgstr "Визначення та обробка параметрів"
+
+msgid "Revert some existing commits"
+msgstr "Вивернути деякі існуючі коміти"
+
+msgid "Remove files from the working tree and from the index"
+msgstr "Видалити файли з робочого дерева та з індексу"
+
+msgid "Send a collection of patches as emails"
+msgstr "Надіслати колекцію латок у вигляді електронних листів"
+
+msgid "Push objects over Git protocol to another repository"
+msgstr "Надіслати обʼєкти за протоколом Git до іншого сховища"
+
+msgid "Git's i18n setup code for shell scripts"
+msgstr "Код налаштування i18n у Git для скриптів оболонки"
+
+msgid "Common Git shell script setup code"
+msgstr "Загальний код налаштування скриптів оболонки Git"
+
+msgid "Restricted login shell for Git-only SSH access"
+msgstr "Обмежений логін оболонки для доступу по SSH лише для Git"
+
+msgid "Summarize 'git log' output"
+msgstr "Підсумувати вивід \"git log\""
+
+msgid "Show various types of objects"
+msgstr "Показати різні типи об’єктів"
+
+msgid "Show branches and their commits"
+msgstr "Показати гілки та їхні коміти"
+
+msgid "Show packed archive index"
+msgstr "Показати індекс запакованого архіву"
+
+msgid "List references in a local repository"
+msgstr "Показати посилання у локальному сховищі"
+
+msgid "Reduce your working tree to a subset of tracked files"
+msgstr "Скоротити робоче дерево до підмножини відстежуваних файлів"
+
+msgid "Add file contents to the staging area"
+msgstr "Додати вміст файлу до області індексації"
+
+msgid "Stash the changes in a dirty working directory away"
+msgstr "Перенести зміни в брудній робочій директорії до схову"
+
+msgid "Show the working tree status"
+msgstr "Показати стан робочого дерева"
+
+msgid "Remove unnecessary whitespace"
+msgstr "Видалити зайві пробіли"
+
+msgid "Initialize, update or inspect submodules"
+msgstr "Ініціалізувати, оновити або перевірити підмодулі"
+
+msgid "Bidirectional operation between a Subversion repository and Git"
+msgstr "Двонаправлена операція між Subversion сховищем та Git"
+
+msgid "Switch branches"
+msgstr "Переключити гілки"
+
+msgid "Read, modify and delete symbolic refs"
+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 "Створює тимчасовий файл із вмістом blob"
+
+msgid "Unpack objects from a packed archive"
+msgstr "Розпакувати обʼєкти із запакованого архіву"
+
+msgid "Register file contents in the working tree to the index"
+msgstr "Зареєструвати вміст файлу робочого дерева в індексі"
+
+msgid "Update the object name stored in a ref safely"
+msgstr "Безпечно оновити назву обʼєкта, що зберігається в посиланні"
+
+msgid "Update auxiliary info file to help dumb servers"
+msgstr "Оновити додатковий інформаційний файл для допомоги \"тупим\" серверам"
+
+msgid "Send archive back to git-archive"
+msgstr "Надіслати архів назад до git-archive"
+
+msgid "Send objects packed back to git-fetch-pack"
+msgstr "Надіслати запаковані обʼєкти назад до git-fetch-pack"
+
+msgid "Show a Git logical variable"
+msgstr "Показати логічну змінну Git"
+
+msgid "Check the GPG signature of commits"
+msgstr "Перевірити GPG-підпис комітів"
+
+msgid "Validate packed Git archive files"
+msgstr "Перевірити запаковані файли Git архіву"
+
+msgid "Check the GPG signature of tags"
+msgstr "Перевірити GPG-підпис тегів"
+
+msgid "Display version information about Git"
+msgstr "Показати інформацію про версію Git"
+
+msgid "Show logs with difference each commit introduces"
+msgstr "Показати журнал з різницею, яку вносить кожен коміт"
+
+msgid "Manage multiple working trees"
+msgstr "Керувати кількома робочими деревами"
+
+msgid "Create a tree object from the current index"
+msgstr "Створити обʼєкт дерева з поточного індексу"
+
+msgid "Defining attributes per path"
+msgstr "Визначення атрибутів для кожного шляху"
+
+msgid "Git command-line interface and conventions"
+msgstr "Інтерфейс та конвенції командного рядка Git"
+
+msgid "A Git core tutorial for developers"
+msgstr "Інструкція по ядру Git для розробників"
+
+msgid "Providing usernames and passwords to Git"
+msgstr "Надання імен користувачів та паролів до Git"
+
+msgid "Git for CVS users"
+msgstr "Git для користувачів CVS"
+
+msgid "Tweaking diff output"
+msgstr "Налаштування виводу різниці"
+
+msgid "A useful minimum set of commands for Everyday Git"
+msgstr "Корисний мінімальний набір команд для повсякденного використання Git"
+
+msgid "Frequently asked questions about using Git"
+msgstr "Поширені запитання про використання Git"
+
+msgid "The bundle file format"
+msgstr "Формат файлу пакунка"
+
+msgid "Chunk-based file formats"
+msgstr "Файлові формати на основі шматків"
+
+msgid "Git commit-graph format"
+msgstr "Формат Git коміт-графа"
+
+msgid "Git index format"
+msgstr "Формат Git індекса"
+
+msgid "Git pack format"
+msgstr "Формат Git пакунка"
+
+msgid "Git cryptographic signature formats"
+msgstr "Формати криптографічного підпису Git"
+
+msgid "A Git Glossary"
+msgstr "Git словник"
+
+msgid "Hooks used by Git"
+msgstr "Гачки, що використовує Git"
+
+msgid "Specifies intentionally untracked files to ignore"
+msgstr "Вказує навмисно невідстежувані файли для ігнорування"
+
+msgid "The Git repository browser"
+msgstr "Браузер сховища Git"
+
+msgid "Map author/committer names and/or E-Mail addresses"
+msgstr "Зробити мапу імен авторів/комітерів та/або адрес електронної пошти"
+
+msgid "Defining submodule properties"
+msgstr "Визначення властивостей підмодулів"
+
+msgid "Git namespaces"
+msgstr "Простори імен Git"
+
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Здібності протоколів v0 та v1"
+
+msgid "Things common to various protocols"
+msgstr "Спільні риси різних протоколів"
+
+msgid "Git HTTP-based protocols"
+msgstr "Git протоколи на основі HTTP"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Як пакунки передаються по дроту"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Протокол Git Wire, версія 2"
+
+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"
+msgstr "Навчальний вступ до Git: частина друга"
+
+msgid "Git web interface (web frontend to Git repositories)"
+msgstr "Веб-інтерфейс Git (веб-фронтенд до сховищ Git)"
+
+msgid "An overview of recommended workflows with Git"
+msgstr "Огляд рекомендованих робочих процесів з Git"
+
+msgid "A tool for managing large Git repositories"
+msgstr "Інструмент для керування великими сховищами Git"
+
+msgid "commit-graph file is too small"
+msgstr "файл коміт-графа занадто малий"
+
+#, c-format
+msgid "commit-graph signature %X does not match signature %X"
+msgstr "підпис коміт-графа %X не збігається з підписом %X"
+
+#, c-format
+msgid "commit-graph version %X does not match version %X"
+msgstr "версія коміт-графа %X не збігається з версією %X"
+
+#, c-format
+msgid "commit-graph hash version %X does not match version %X"
+msgstr "хеш версія коміт-графа %X не збігається з версією %X"
+
+#, c-format
+msgid "commit-graph file is too small to hold %u chunks"
+msgstr "файл коміт-графа занадто малий, щоб вмістити %u шматків"
+
+msgid "commit-graph has no base graphs chunk"
+msgstr "коміт-граф не має шматка базових графів"
+
+msgid "commit-graph chain does not match"
+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 "неприпустимий ланцюжок коміт-графа: рядок \"%s\" не є хешем"
+
+msgid "unable to find all commit-graph files"
+msgstr "не вдалося знайти всі файли коміт-графа"
+
+msgid "invalid commit position. commit-graph is likely corrupt"
+msgstr "неприпустима позиція коміту, ймовірно, коміт-граф пошкоджено"
+
+#, c-format
+msgid "could not find commit %s"
+msgstr "не вдалося знайти коміт %s"
+
+msgid "commit-graph requires overflow generation data but has none"
+msgstr "коміт-граф потребує даних генерації переповнення, але їх немаєданих"
+
+msgid "Loading known commits in commit graph"
+msgstr "Завантаження відомих комітів у коміт-графі"
+
+msgid "Expanding reachable commits in commit graph"
+msgstr "Розширення досяжних комітів у коміт-графі"
+
+msgid "Clearing commit marks in commit graph"
+msgstr "Очищення позначок комітів у коміт-графі"
+
+msgid "Computing commit graph topological levels"
+msgstr "Обчислення топологічних рівнів коміт-графа"
+
+msgid "Computing commit graph generation numbers"
+msgstr "Обчислення номерів генерації коміт-графа"
+
+msgid "Computing commit changed paths Bloom filters"
+msgstr "Обчислення фільтрів Блума для шляхів, змінених комітом"
+
+msgid "Collecting referenced commits"
+msgstr "Збір посилань на коміти"
+
+#, c-format
+msgid "Finding commits for commit graph in %<PRIuMAX> pack"
+msgid_plural "Finding commits for commit graph in %<PRIuMAX> packs"
+msgstr[0] "Пошук комітів для коміт-графа у %<PRIuMAX> пакунку"
+msgstr[1] "Пошук комітів для коміт-графа у %<PRIuMAX> пакунках"
+msgstr[2] "Пошук комітів для коміт-графа у %<PRIuMAX> пакунках"
+
+#, c-format
+msgid "error adding pack %s"
+msgstr "помилка додавання пакету %s"
+
+#, c-format
+msgid "error opening index for %s"
+msgstr "помилка відкриття індексу для %s"
+
+msgid "Finding commits for commit graph among packed objects"
+msgstr "Пошук комітів для коміт-графа серед запакованих обʼєктів"
+
+msgid "Finding extra edges in commit graph"
+msgstr "Пошук додаткових ребер у коміт-графі"
+
+msgid "failed to write correct number of base graph ids"
+msgstr "не вдалося записати правильну кількість ідентифікаторів базових графів"
+
+msgid "unable to create temporary graph layer"
+msgstr "не вдалося створити тимчасовий шар графа"
+
+#, c-format
+msgid "unable to adjust shared permissions for '%s'"
+msgstr "не вдалося налаштувати спільні дозволи для \"%s\""
+
+#, c-format
+msgid "Writing out commit graph in %d pass"
+msgid_plural "Writing out commit graph in %d passes"
+msgstr[0] "Виведення коміт-графа за %d прохід"
+msgstr[1] "Виведення коміт-графа за %d проходи"
+msgstr[2] "Виведення коміт-графа за %d проходів"
+
+msgid "unable to open commit-graph chain file"
+msgstr "не вдалося відкрити ланцюжковий файл коміт-графа"
+
+msgid "failed to rename base commit-graph file"
+msgstr "не вдалося перейменувати базовий файл коміт-графа"
+
+msgid "failed to rename temporary commit-graph file"
+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 "Сканування злитих комітів"
+
+msgid "Merging commit-graph"
+msgstr "Злиття коміт-графа"
+
+msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
+msgstr "спроба записати коміт-граф, але \"core.commitGraph\" відключено"
+
+msgid "too many commits to write graph"
+msgstr "занадто багато комітів, щоб записати граф"
+
+msgid "the commit-graph file has incorrect checksum and is likely corrupt"
+msgstr "файл коміт-графа має невірну контрольну суму і, ймовірно, пошкоджений"
+
+#, c-format
+msgid "commit-graph has incorrect OID order: %s then %s"
+msgstr "коміт-граф має невірну OID послідовність: %s потім %s"
+
+#, c-format
+msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
+msgstr "коміт-граф має невірне fanout значення: fanout[%d] = %u != %u"
+
+#, c-format
+msgid "failed to parse commit %s from commit-graph"
+msgstr "не вдалося розібрати коміт %s з графа комітв"
+
+#, c-format
+msgid "failed to parse commit %s from object database for commit-graph"
+msgstr "не вдалося розібрати коміт %s з бази даних обʼєктів для коміт-графа"
+
+#, c-format
+msgid "root tree OID for commit %s in commit-graph is %s != %s"
+msgstr "OID кореневого дерева для коміту %s у коміт-графі є %s != %s"
+
+#, c-format
+msgid "commit-graph parent list for commit %s is too long"
+msgstr "список батьків для коміту %s коміт-графа занадто довгий"
+
+#, c-format
+msgid "commit-graph parent for %s is %s != %s"
+msgstr "батько для %s коміт-графа є %s != %s"
+
+#, c-format
+msgid "commit-graph parent list for commit %s terminates early"
+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 "генерація коміт-графа для коміту %s є %<PRIuMAX> < %<PRIuMAX>"
+
+#, c-format
+msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
+msgstr "дата коміту для коміту %s у коміт-графі є %<PRIuMAX> != %<PRIuMAX>"
+
+msgid "Verifying commits in commit graph"
+msgstr "Перевірка комітів у коміт-графі"
+
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s не є комітом!"
+
+msgid ""
+"Support for <GIT_DIR>/info/grafts is deprecated\n"
+"and will be removed in a future Git version.\n"
+"\n"
+"Please use \"git replace --convert-graft-file\"\n"
+"to convert the grafts into replace refs.\n"
+"\n"
+"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 "Коміт %s має недостовірний GPG-підпис, нібито від %s."
+
+#, c-format
+msgid "Commit %s has a bad GPG signature allegedly by %s."
+msgstr "Коміт %s має невірний GPG-підпис, нібито від %s."
+
+#, c-format
+msgid "Commit %s does not have a GPG signature."
+msgstr "Коміт %s не має GPG підпису."
+
+#, c-format
+msgid "Commit %s has a good GPG signature by %s\n"
+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 "немає інформації про компілятор\n"
+
+msgid "no libc information available\n"
+msgstr "немає інформації про libc\n"
+
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "не вдалося визначити вільний розмір диска для \"%s\""
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "не вдалося отримати інформацію для \"%s\""
+
+#, c-format
+msgid "[GLE %ld] health thread could not open '%ls'"
+msgstr "[GLE %ld] потік стану не зміг відкрити \"%ls\""
+
+#, c-format
+msgid "[GLE %ld] health thread getting BHFI for '%ls'"
+msgstr "[GLE %ld] потік стану отримує BHFI для \"%ls\""
+
+#, c-format
+msgid "could not convert to wide characters: '%s'"
+msgstr "не вдалося перетворити в широкі символи: \"%s\""
+
+#, c-format
+msgid "BHFI changed '%ls'"
+msgstr "BHFI змінено \"%ls\""
+
+#, c-format
+msgid "unhandled case in 'has_worktree_moved': %d"
+msgstr "необроблений випадок у \"has_worktree_moved\": %d"
+
+#, c-format
+msgid "health thread wait failed [GLE %ld]"
+msgstr "очікування потоку стану завершилося невдало [GLE %ld]"
+
+#, c-format
+msgid "Invalid path: %s"
+msgstr "Неприпустимий шлях: %s"
+
+msgid "Unable to create FSEventStream."
+msgstr "Не вдалося створити FSEventStream."
+
+msgid "Failed to start the FSEventStream"
+msgstr "Не вдалося запустити потік FSEventStream"
+
+#, c-format
+msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
+msgstr "[GLE %ld] не вдалося конвертувати шлях у UTF-8: \"%.*ls\""
+
+#, c-format
+msgid "[GLE %ld] could not watch '%s'"
+msgstr "[GLE %ld] стеження завершилось невдало \"%s\""
+
+#, c-format
+msgid "[GLE %ld] could not get longname of '%s'"
+msgstr "[GLE %ld] не вдалося отримати довгу назву \"%s\""
+
+#, c-format
+msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
+msgstr "ReadDirectoryChangedW завершилось невдало на \"%s\" [GLE %ld]"
+
+#, c-format
+msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
+msgstr "GetOverlappedResult завершилось невдало на \"%s\" [GLE %ld]"
+
+#, c-format
+msgid "could not read directory changes [GLE %ld]"
+msgstr "не вдалося прочитати зміни директорії [GLE %ld]"
+
+#, c-format
+msgid "opendir('%s') failed"
+msgstr "opendir(\"%s\") завершився невдало"
+
+#, c-format
+msgid "lstat('%s') failed"
+msgstr "lstat(\"%s\") завершився невдало"
+
+#, c-format
+msgid "strbuf_readlink('%s') failed"
+msgstr "strbuf_readlink(\"%s\") завершився невдало"
+
+#, c-format
+msgid "closedir('%s') failed"
+msgstr "closedir(\"%s\") завершився невдало"
+
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] не вдалося відкрити для читання \"%ls\""
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] не вдалося отримати інформацію про протокол для \"%ls\""
+
+#, c-format
+msgid "failed to copy SID (%ld)"
+msgstr "не вдалося скопіювати SID (%ld)"
+
+#, c-format
+msgid "failed to get owner for '%s' (%ld)"
+msgstr "не вдалося отримати власника для \"%s\" (%ld)"
+
+msgid "memory exhausted"
+msgstr "памʼять вичерпано"
+
+msgid "Success"
+msgstr "Успіх"
+
+msgid "No match"
+msgstr "Немає збігів"
+
+msgid "Invalid regular expression"
+msgstr "Неприпустимий регулярний вираз"
+
+msgid "Invalid collation character"
+msgstr "Неприпустимий символ зведення"
+
+msgid "Invalid character class name"
+msgstr "Неприпустима назва класу символів"
+
+msgid "Trailing backslash"
+msgstr "Кінцева зворотна коса риска"
+
+msgid "Invalid back reference"
+msgstr "Неприпустиме зворотнє посилання"
+
+msgid "Unmatched [ or [^"
+msgstr "Непарна [ або [^"
+
+msgid "Unmatched ( or \\("
+msgstr "Непарна ( або \\("
+
+msgid "Unmatched \\{"
+msgstr "Непарна \\{"
+
+msgid "Invalid content of \\{\\}"
+msgstr "Неприпустимий вміст для \\{\\}"
+
+msgid "Invalid range end"
+msgstr "Неприпустимий кінець діапазону"
+
+msgid "Memory exhausted"
+msgstr "Памʼять вичерпано"
+
+msgid "Invalid preceding regular expression"
+msgstr "Неприпустимий попередній регулярний вираз"
+
+msgid "Premature end of regular expression"
+msgstr "Передчасне завершення регулярного виразу"
+
+msgid "Regular expression too big"
+msgstr "Занадто великий регулярний вираз"
+
+msgid "Unmatched ) or \\)"
+msgstr "Непарна ) або \\)"
+
+msgid "No previous regular expression"
+msgstr "Немає попереднього регулярного виразу"
+
+msgid "could not send IPC command"
+msgstr "не вдалося відправити IPC команду"
+
+msgid "could not read IPC response"
+msgstr "не вдалося прочитати IPC відповідь"
+
+#, c-format
+msgid "could not start accept_thread '%s'"
+msgstr "не вдалося розпочати accept_thread \"%s\""
+
+#, c-format
+msgid "could not start worker[0] for '%s'"
+msgstr "не вдалося запустити worker[0] для \"%s\""
+
+#, c-format
+msgid "ConnectNamedPipe failed for '%s' (%lu)"
+msgstr "ConnectNamedPipe завершився невдало для \"%s\" (%lu)"
+
+#, c-format
+msgid "could not create fd from pipe for '%s'"
+msgstr "не вдалося створити fd з каналу для \"%s\""
+
+#, c-format
+msgid "could not start thread[0] for '%s'"
+msgstr "не вдалося запустити thread[0] для \"%s\""
+
+#, c-format
+msgid "wait for hEvent failed for '%s'"
+msgstr "очікування на hEvent не вдалося для \"%s\""
+
+msgid "cannot resume in the background, please use 'fg' to resume"
+msgstr ""
+"неможливо поновити роботу у фоновому режимі; будь ласка, скористайтесь "
+"\"fg\" для поновлення"
+
+msgid "cannot restore terminal settings"
+msgstr "не вдалося відновити налаштування термінала"
+
+#, c-format
+msgid ""
+"exceeded maximum include depth (%d) while including\n"
+"\t%s\n"
+"from\n"
+"\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 "відносні конфігураційні включення мають надходити з файлів"
+
+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"
+msgstr "неприпустимий формат конфігурації: %s"
+
+#, c-format
+msgid "missing environment variable name for configuration '%.*s'"
+msgstr "відсутня назва змінної оточення для конфігурації \"%.*s\""
+
+#, c-format
+msgid "missing environment variable '%s' for configuration '%.*s'"
+msgstr "відсутня змінна оточення \"%s\" для конфігурації \"%.*s\""
+
+#, c-format
+msgid "key does not contain a section: %s"
+msgstr "ключ не містить розділу: %s"
+
+#, c-format
+msgid "key does not contain variable name: %s"
+msgstr "ключ не містить назви змінної: %s"
+
+#, c-format
+msgid "invalid key: %s"
+msgstr "неприпустимий ключ: %s"
+
+#, c-format
+msgid "invalid key (newline): %s"
+msgstr "неприпустимий ключ (новий рядок): %s"
+
+msgid "empty config key"
+msgstr "порожній ключ конфігурації"
+
+#, c-format
+msgid "bogus config parameter: %s"
+msgstr "хибний параметр конфігурації: %s"
+
+#, c-format
+msgid "bogus format in %s"
+msgstr "хибний формат у %s"
+
+#, c-format
+msgid "bogus count in %s"
+msgstr "хибна кількість у %s"
+
+#, c-format
+msgid "too many entries in %s"
+msgstr "забагато записів у %s"
+
+#, c-format
+msgid "missing config key %s"
+msgstr "відсутній ключ конфігурації %s"
+
+#, c-format
+msgid "missing config value %s"
+msgstr "відсутнє значення конфігурації %s"
+
+#, c-format
+msgid "bad config line %d in blob %s"
+msgstr "невірний конфігураційний рядок %d у blob %s"
+
+#, c-format
+msgid "bad config line %d in file %s"
+msgstr "невірний конфігураційний рядок %d у файлі %s"
+
+#, c-format
+msgid "bad config line %d in standard input"
+msgstr "невірний конфігураційний рядок %d у стандартному вводі"
+
+#, c-format
+msgid "bad config line %d in submodule-blob %s"
+msgstr "невірний конфігураційний рядок %d у підмодулі-blob %s"
+
+#, c-format
+msgid "bad config line %d in command line %s"
+msgstr "невірний конфігураційний рядок %d у командному рядку %s"
+
+#, c-format
+msgid "bad config line %d in %s"
+msgstr "невірний конфігураційний рядок %d в %s"
+
+msgid "out of range"
+msgstr "поза межами діапазону"
+
+msgid "invalid unit"
+msgstr "неприпустима одиниця виміру"
+
+#, c-format
+msgid "bad numeric config value '%s' for '%s': %s"
+msgstr "невірне числове значення конфігурації \"%s\" для \"%s\": %s"
+
+#, c-format
+msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
+msgstr "невірне числове значення конфігурації \"%s\" для \"%s\" у blob %s: %s"
+
+#, c-format
+msgid "bad numeric config value '%s' for '%s' in file %s: %s"
+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 "невірне числове значення конфігурації \"%s\" для \"%s\" у \"%s\": %s"
+
+#, c-format
+msgid "invalid value for variable %s"
+msgstr "неприпустиме значення для змінної %s"
+
+#, c-format
+msgid "ignoring unknown core.fsync component '%s'"
+msgstr "ігнорування невідомого компонента core.fsync \"%s\""
+
+#, c-format
+msgid "bad boolean config value '%s' for '%s'"
+msgstr "невірне булеве значення конфігурації \"%s\" для \"%s\""
+
+#, c-format
+msgid "failed to expand user dir in: '%s'"
+msgstr "не вдалося визначити директорію користувача в: \"%s\""
+
+#, c-format
+msgid "'%s' for '%s' is not a valid timestamp"
+msgstr "\"%s\" для \"%s\" не є припустимою міткою часу"
+
+#, c-format
+msgid "abbrev length out of range: %d"
+msgstr "довжина скорочення поза діапазоном: %d"
+
+#, c-format
+msgid "bad zlib compression level %d"
+msgstr "невірний рівень zlib компресії %d"
+
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar має бути лише одним символом ASCII"
+
+#, c-format
+msgid "ignoring unknown core.fsyncMethod value '%s'"
+msgstr "ігнорування невідомого значення core.fsyncMethod \"%s\""
+
+msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
+msgstr "core.fsyncObjectFiles застаріла; натомість використовуйте core.fsync"
+
+#, c-format
+msgid "invalid mode for object creation: %s"
+msgstr "неприпустимий режим створення обʼєкта: %s"
+
+#, c-format
+msgid "malformed value for %s"
+msgstr "невірно сформоване значення для %s"
+
+#, c-format
+msgid "malformed value for %s: %s"
+msgstr "невірно сформоване значення для %s: %s"
+
+msgid "must be one of nothing, matching, simple, upstream or current"
+msgstr "має бути одним з nothing, matching, simple, upstream або current"
+
+#, c-format
+msgid "unable to load config blob object '%s'"
+msgstr "не вдалося завантажити config blob обʼєкт \"%s\""
+
+#, c-format
+msgid "reference '%s' does not point to a blob"
+msgstr "посилання \"%s\" не вказує на blob"
+
+#, c-format
+msgid "unable to resolve config blob '%s'"
+msgstr "не вдалося розпізнати config blob \"%s\""
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "не вдалося розібрати %s"
+
+msgid "unable to parse command-line config"
+msgstr "не вдалося розібрати конфігурацію командного рядка"
+
+msgid "unknown error occurred while reading the configuration files"
+msgstr "невідома помилка виникла під час читання конфігураційних файлів"
+
+#, c-format
+msgid "Invalid %s: '%s'"
+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"
+msgstr "не вдалося розібрати \"%s\" з конфігурації командного рядка"
+
+#, c-format
+msgid "bad config variable '%s' in file '%s' at line %d"
+msgstr "невірна конфігураційна змінна \"%s\" у файлі \"%s\", рядок \"%d\""
+
+#, c-format
+msgid "invalid section name '%s'"
+msgstr "неприпустима назва секції \"%s\""
+
+#, c-format
+msgid "%s has multiple values"
+msgstr "%s має кілька значень"
+
+#, c-format
+msgid "failed to write new configuration file %s"
+msgstr "не вдалося записати новий конфігураційний файл %s"
+
+#, c-format
+msgid "could not lock config file %s"
+msgstr "не вдалося зафіксувати файл конфігурації %s"
+
+#, c-format
+msgid "opening %s"
+msgstr "відкриття %s"
+
+#, c-format
+msgid "invalid config file %s"
+msgstr "неприпустимий конфігураційний файл %s"
+
+#, c-format
+msgid "fstat on %s failed"
+msgstr "не вдалося виконати fstat на %s"
+
+#, c-format
+msgid "unable to mmap '%s'%s"
+msgstr "не вдалося виконати mmap \"%s\"%s"
+
+#, c-format
+msgid "chmod on %s failed"
+msgstr "не вдалося виконати chmod на %s"
+
+#, c-format
+msgid "could not write config file %s"
+msgstr "не вдалося записати конфігураційний файл %s"
+
+#, c-format
+msgid "could not set '%s' to '%s'"
+msgstr "не вдалося встановити \"%s\" в \"%s\""
+
+#, c-format
+msgid "invalid section name: %s"
+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 "віддалене призначеня відключилося при першому контакті"
+
+msgid ""
+"Could not read from remote repository.\n"
+"\n"
+"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 "сервер не підтримує \"%s\""
+
+#, c-format
+msgid "server doesn't support feature '%s'"
+msgstr "сервер не підтримує особливість \"%s\""
+
+msgid "expected flush after capabilities"
+msgstr "очікувалось flush після здібностей"
+
+#, c-format
+msgid "ignoring capabilities after first line '%s'"
+msgstr "ігнорування здібностей після першого рядка \"%s\""
+
+msgid "protocol error: unexpected capabilities^{}"
+msgstr "помилка протоколу: неочікувані здібності^{}"
+
+#, c-format
+msgid "protocol error: expected shallow sha-1, got '%s'"
+msgstr "помилка протоколу: очікувалось неглибоке sha-1, отримано \"%s\""
+
+msgid "repository on the other end cannot be shallow"
+msgstr "сховище на іншому кінці не може бути неглибоким"
+
+msgid "invalid packet"
+msgstr "неприпустимий пакет"
+
+#, c-format
+msgid "protocol error: unexpected '%s'"
+msgstr "помилка протоколу: неочікуване \"%s\""
+
+#, c-format
+msgid "unknown object format '%s' specified by server"
+msgstr "невідомий формат обʼєкта \"%s\", вказаний сервером"
+
+#, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "помилка у рядку відповіді bundle-uri %d: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "очікувалось flush після виводу bundle-uri"
+
+msgid "expected response end packet after ref listing"
+msgstr "очікувалось response end пакет після виводу посилань"
+
+#, c-format
+msgid "invalid ls-refs response: %s"
+msgstr "неприпустима ls-refs відповідь: %s"
+
+msgid "expected flush after ref listing"
+msgstr "очікувалось flush після виводу посилань"
+
+#, c-format
+msgid "protocol '%s' is not supported"
+msgstr "протокол \"%s\" не підтримується"
+
+msgid "unable to set SO_KEEPALIVE on socket"
+msgstr "не вдалося встановити SO_KEEPALIVE сокету"
+
+#, c-format
+msgid "Looking up %s ... "
+msgstr "Пошук %s ... "
+
+#, c-format
+msgid "unable to look up %s (port %s) (%s)"
+msgstr "не вдалося знайти %s (порт %s) (%s)"
+
+#. TRANSLATORS: this is the end of "Looking up %s ... "
+
+#, c-format
+msgid ""
+"done.\n"
+"Connecting to %s (port %s) ... "
+msgstr ""
+"готово.\n"
+"Підключення до %s (порт %s) ... "
+
+#, c-format
+msgid ""
+"unable to connect to %s:\n"
+"%s"
+msgstr ""
+"не вдалося приєднатися до %s:\n"
+"%s"
+
+#. TRANSLATORS: this is the end of "Connecting to %s (port %s) ... "
+
+msgid "done."
+msgstr "готово."
+
+#, c-format
+msgid "unable to look up %s (%s)"
+msgstr "не вдалося знайти %s (%s)"
+
+#, c-format
+msgid "unknown port %s"
+msgstr "невідомий порт %s"
+
+#, c-format
+msgid "strange hostname '%s' blocked"
+msgstr "дивне імʼя хоста \"%s\" заблоковано"
+
+#, c-format
+msgid "strange port '%s' blocked"
+msgstr "дивний порт \"%s\" заблоковано"
+
+#, c-format
+msgid "cannot start proxy %s"
+msgstr "неможливо запустити проксі %s"
+
+msgid "no path specified; see 'git help pull' for valid url syntax"
+msgstr "не вказано шлях; дивіться \"git help pull\" для чинного url синтаксису"
+
+msgid "newline is forbidden in git:// hosts and repo paths"
+msgstr "новий рядок у хостах git:// та шляхах репозиторіїв заборонено"
+
+msgid "ssh variant 'simple' does not support -4"
+msgstr "ssh опція \"simple\" не підтримує -4"
+
+msgid "ssh variant 'simple' does not support -6"
+msgstr "ssh опція \"simple\" не підтримує -6"
+
+msgid "ssh variant 'simple' does not support setting port"
+msgstr "ssh опція \"simple\" не підтримує встановлення порту"
+
+#, c-format
+msgid "strange pathname '%s' blocked"
+msgstr "дивне імʼя шляху \"%s\" заблоковано"
+
+msgid "unable to fork"
+msgstr "неможливо розгалужити"
+
+msgid "Could not run 'git rev-list'"
+msgstr "Не вдалося запустити \"git rev-list\""
+
+msgid "failed write to rev-list"
+msgstr "не вдалося записати до rev-list"
+
+msgid "failed to close rev-list's stdin"
+msgstr "не вдалося закрити stdin для rev-list"
+
+#, c-format
+msgid "illegal crlf_action %d"
+msgstr "неприпустиме crlf_action %d"
+
+#, c-format
+msgid "CRLF would be replaced by LF in %s"
+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 "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 "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 "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"
+msgstr "не вдалося закодувати \"%s\" з %s в %s"
+
+#, c-format
+msgid "encoding '%s' from %s to %s and back is not the same"
+msgstr "кодування \"%s\" з %s в %s і назад не однакове"
+
+#, c-format
+msgid "cannot fork to run external filter '%s'"
+msgstr "неможливо розгалужити для запуску зовнішнього фільтра \"%s\""
+
+#, c-format
+msgid "cannot feed the input to external filter '%s'"
+msgstr "неможливо подати вхідні дані на зовнішній фільтр \"%s\""
+
+#, c-format
+msgid "external filter '%s' failed %d"
+msgstr "помилка зовнішнього фільтра \"%s\", код: %d"
+
+#, c-format
+msgid "read from external filter '%s' failed"
+msgstr "не вдалося прочитати з зовнішнього фільтра \"%s\""
+
+#, c-format
+msgid "external filter '%s' failed"
+msgstr "помилка зовнішнього фільтра \"%s\""
+
+msgid "unexpected filter type"
+msgstr "несподіваний тип фільтра"
+
+msgid "path name too long for external filter"
+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 "true/false не є допустимими кодуваннями робочого дерева"
+
+#, c-format
+msgid "%s: clean filter '%s' failed"
+msgstr "%s: помилка фільтра очистки \"%s\""
+
+#, c-format
+msgid "%s: smudge filter %s failed"
+msgstr "%s: помилка фільтра розмиття %s"
+
+#, c-format
+msgid "skipping credential lookup for key: credential.%s"
+msgstr "пропуск пошуку облікових даних для ключа: credential.%s"
+
+msgid "refusing to work with credential missing host field"
+msgstr "відмовлено в роботі з відсутнім полем хоста в облікових даних"
+
+msgid "refusing to work with credential missing protocol field"
+msgstr "відмовлено в роботі з відсутнім полем протоколу облікових даних"
+
+#, c-format
+msgid "url contains a newline in its %s component: %s"
+msgstr "url містить новий рядок у %s компоненті: %s"
+
+#, c-format
+msgid "url has no scheme: %s"
+msgstr "url не має схеми: %s"
+
+#, c-format
+msgid "credential url cannot be parsed: %s"
+msgstr "неможливо розібрати url облікових даних: %s"
+
+msgid "in the future"
+msgstr "у майбутньому"
+
+#, c-format
+msgid "%<PRIuMAX> second ago"
+msgid_plural "%<PRIuMAX> seconds ago"
+msgstr[0] "%<PRIuMAX> секунду тому"
+msgstr[1] "%<PRIuMAX> секунди тому"
+msgstr[2] "%<PRIuMAX> секунд тому"
+
+#, c-format
+msgid "%<PRIuMAX> minute ago"
+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] "%<PRIuMAX> годину тому"
+msgstr[1] "%<PRIuMAX> години тому"
+msgstr[2] "%<PRIuMAX> годин тому"
+
+#, c-format
+msgid "%<PRIuMAX> day ago"
+msgid_plural "%<PRIuMAX> days ago"
+msgstr[0] "%<PRIuMAX> день тому"
+msgstr[1] "%<PRIuMAX> дні тому"
+msgstr[2] "%<PRIuMAX> днів тому"
+
+#, c-format
+msgid "%<PRIuMAX> week ago"
+msgid_plural "%<PRIuMAX> weeks ago"
+msgstr[0] "%<PRIuMAX> тиждень тому"
+msgstr[1] "%<PRIuMAX> тижні тому"
+msgstr[2] "%<PRIuMAX> тижнів тому"
+
+#, c-format
+msgid "%<PRIuMAX> month ago"
+msgid_plural "%<PRIuMAX> months ago"
+msgstr[0] "%<PRIuMAX> місяць тому"
+msgstr[1] "%<PRIuMAX> місяці тому"
+msgstr[2] "%<PRIuMAX> місяців тому"
+
+#, c-format
+msgid "%<PRIuMAX> year"
+msgid_plural "%<PRIuMAX> years"
+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] "%s, %<PRIuMAX> місяць тому"
+msgstr[1] "%s, %<PRIuMAX> місяці тому"
+msgstr[2] "%s, %<PRIuMAX> місяців тому"
+
+#, c-format
+msgid "%<PRIuMAX> year ago"
+msgid_plural "%<PRIuMAX> years ago"
+msgstr[0] "%<PRIuMAX> рік тому"
+msgstr[1] "%<PRIuMAX> роки тому"
+msgstr[2] "%<PRIuMAX> років тому"
+
+msgid "Propagating island marks"
+msgstr "Розповсюдження острівних позначок"
+
+#, c-format
+msgid "bad tree object %s"
+msgstr "невірний обʼєкт дерева %s"
+
+#, c-format
+msgid "failed to load island regex for '%s': %s"
+msgstr "не вдалося завантажити island регвир для \"%s\": %s"
+
+#, c-format
+msgid "island regex from config has too many capture groups (max=%d)"
+msgstr "регвир острова з конфігурації має забагато груп захоплення (max=%d)"
+
+#, c-format
+msgid "Marked %d islands, done.\n"
+msgstr "Позначено %d островів, готово.\n"
+
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "неприпустиме --%s значення \"%s\""
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "не вдалося заархівувати відсутню директорію \"%s\""
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "не вдалося відкрити директорію \"%s\""
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "пропускання \"%s\", який не є ні файлом, ні директорією"
+
+msgid "could not duplicate stdout"
+msgstr "не вдалося продублювати stdout"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "не вдалося додати директорію \"%s\" до архіватора"
+
+msgid "failed to write archive"
+msgstr "не вдалося записати архів"
+
+msgid "--merge-base does not work with ranges"
+msgstr "--merge-base не працює з діапазонами"
+
+msgid "--merge-base only works with commits"
+msgstr "--merge-base працює лише з комітами"
+
+msgid "unable to get HEAD"
+msgstr "не вдалося отримати HEAD"
+
+msgid "no merge base found"
+msgstr "базу злиття не знайдено"
+
+msgid "multiple merge bases found"
+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 [<опції>] <шлях> <шлях>"
+
+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 " Не вдалося розібрати відсоток відсікання dirstat \"%s\"\n"
+
+#, c-format
+msgid "  Unknown dirstat parameter '%s'\n"
+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 "Невідоме значення конфігураційної змінної \"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 "зовнішній 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"
+msgstr "опції \"%s\", \"%s\", \"%s\" та \"%s\" неможливо використовувати разом"
+
+#, c-format
+msgid "options '%s' and '%s' cannot be used together, use '%s' with '%s'"
+msgstr ""
+"опції \"%s\" і \"%s\" неможливо використати разом, використовуйте \"%s\" з "
+"\"%s\""
+
+#, c-format
+msgid ""
+"options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
+msgstr ""
+"опції \"%s\" і \"%s\" неможливо використати разом, використовуйте \"%s\" з "
+"\"%s\" та \"%s\""
+
+#, c-format
+msgid "invalid --stat value: %s"
+msgstr "неприпустиме --stat значення: %s"
+
+#, c-format
+msgid "%s expects a numerical value"
+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 "невідома зміна класу \"%c\" у --diff-filter=%s"
+
+#, c-format
+msgid "unknown value after ws-error-highlight=%.*s"
+msgstr "невідоме значення після ws-error-highlight=%.*s"
+
+#, c-format
+msgid "unable to resolve '%s'"
+msgstr "не вдалося розпізнати \"%s\""
+
+#, c-format
+msgid "%s expects <n>/<m> form"
+msgstr "%s очікує <n>/<m> форму"
+
+#, c-format
+msgid "%s expects a character, got '%s'"
+msgstr "%s очікує символ, отримано \"%s\""
+
+#, c-format
+msgid "bad --color-moved argument: %s"
+msgstr "невірний --color-moved аргумент: %s"
+
+#, c-format
+msgid "invalid mode '%s' in --color-moved-ws"
+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"
+msgstr "неприпустимий аргумент до %s"
+
+#, c-format
+msgid "invalid regex given to -I: '%s'"
+msgstr "неприпустимий regex, переданий до -I: \"%s\""
+
+#, c-format
+msgid "failed to parse --submodule option parameter: '%s'"
+msgstr "не вдалося розібрати параметр опції --submodule: \"%s\""
+
+#, c-format
+msgid "bad --word-diff argument: %s"
+msgstr "невірний --word-diff аргумент: %s"
+
+msgid "Diff output format options"
+msgstr "Варіанти формату виводу різниці"
+
+msgid "generate patch"
+msgstr "згенерувати латку"
+
+msgid "<n>"
+msgstr "<n>"
+
+msgid "generate diffs with <n> lines context"
+msgstr "згенерувати різниці з контекстом в <n> рядків"
+
+msgid "generate the diff in raw format"
+msgstr "згенерувати різницю у форматі raw"
+
+msgid "synonym for '-p --raw'"
+msgstr "синонім для \"-p --raw\""
+
+msgid "synonym for '-p --stat'"
+msgstr "синонім для \"-p --stat\""
+
+msgid "machine friendly --stat"
+msgstr "машинний вивід --stat"
+
+msgid "output only the last line of --stat"
+msgstr "вивести лише останній рядок --stat"
+
+msgid "<param1,param2>..."
+msgstr "<параметр1,параметр2>..."
+
+msgid ""
+"output the distribution of relative amount of changes for each sub-directory"
+msgstr "вивести розподіл відносної кількості змін для кожної піддиректорії"
+
+msgid "synonym for --dirstat=cumulative"
+msgstr "синонім для --dirstat=cumulative"
+
+msgid "synonym for --dirstat=files,param1,param2..."
+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 "стислі підсумки, такі як створення, перейменування та зміни режимів"
+
+msgid "show only names of changed files"
+msgstr "показувати тільки назви змінених файлів"
+
+msgid "show only names and status of changed files"
+msgstr "показувати тільки назви та статус змінених файлів"
+
+msgid "<width>[,<name-width>[,<count>]]"
+msgstr "<ширина>[,<ширина-назви>[,<кількість>]]"
+
+msgid "generate diffstat"
+msgstr "згенерувати diffstat"
+
+msgid "<width>"
+msgstr "<ширина>"
+
+msgid "generate diffstat with a given width"
+msgstr "згенерувати diffstat із заданою шириною"
+
+msgid "generate diffstat with a given name width"
+msgstr "згенерувати diffstat із заданою шириною назви"
+
+msgid "generate diffstat with a given graph width"
+msgstr "згенерувати diffstat із заданою шириною графіка"
+
+msgid "<count>"
+msgstr "<кількість>"
+
+msgid "generate diffstat with limited lines"
+msgstr "згенерувати diffstat з обмеженою кількістю рядків"
+
+msgid "generate compact summary in diffstat"
+msgstr "згенерувати компактний підсумок у diffstat"
+
+msgid "output a binary diff that can be applied"
+msgstr "вивести бінарну різницю, яку можна застосувати"
+
+msgid "show full pre- and post-image object names on the \"index\" lines"
+msgstr ""
+"показувати повні назви обʼєктів до та після зображення в \"index\" рядках"
+
+msgid "show colored diff"
+msgstr "показати кольорову різницю"
+
+msgid "<kind>"
+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 "<префікс>"
+
+msgid "show the given source prefix instead of \"a/\""
+msgstr "показувати заданий префікс джерела замість \"a/\""
+
+msgid "show the given destination prefix instead of \"b/\""
+msgstr "показувати заданий префікс призначення замість \"b/\""
+
+msgid "prepend an additional prefix to every line of output"
+msgstr "додавати префікс до кожного рядка виводу"
+
+msgid "do not show any source or destination prefix"
+msgstr "не показувати жодного префікса джерела або призначення"
+
+msgid "use default prefixes a/ and b/"
+msgstr "використовувати префікси за замовчуванням a/ та b/"
+
+msgid "show context between diff hunks up to the specified number of lines"
+msgstr "показувати контекст між шматками різниці до вказаної кількості рядків"
+
+msgid "<char>"
+msgstr "<символ>"
+
+msgid "specify the character to indicate a new line instead of '+'"
+msgstr "вкажіть символ для позначення нового рядка замість \"+\""
+
+msgid "specify the character to indicate an old line instead of '-'"
+msgstr "вкажіть символ для позначення старого рядка замість \"-\""
+
+msgid "specify the character to indicate a context instead of ' '"
+msgstr "вкажіть символ для позначення контексту замість \" \""
+
+msgid "Diff rename options"
+msgstr "Варіанти перейменування різниці"
+
+msgid "<n>[/<m>]"
+msgstr "<n>[/<m>]"
+
+msgid "break complete rewrite changes into pairs of delete and create"
+msgstr "розбити повний перезапис змін на пари delete та create"
+
+msgid "detect renames"
+msgstr "виявляти перейменування"
+
+msgid "omit the preimage for deletes"
+msgstr "пропускати попереднє зображення для видалень"
+
+msgid "detect copies"
+msgstr "виявляти копії"
+
+msgid "use unmodified files as source to find copies"
+msgstr "використовувати незмінені файли як джерело для пошуку копій"
+
+msgid "disable rename detection"
+msgstr "вимкнути виявлення перейменування"
+
+msgid "use empty blobs as rename source"
+msgstr "використовувати порожні blobs як джерело перейменування"
+
+msgid "continue listing the history of a file beyond renames"
+msgstr "продовжити виведення історії файлу після перейменування"
+
+msgid ""
+"prevent rename/copy detection if the number of rename/copy targets exceeds "
+"given limit"
+msgstr ""
+"запобігати виявленню перейменування/копіювання, якщо кількість обʼєктів "
+"перейменування/копіювання перевищує заданий ліміт"
+
+msgid "Diff algorithm options"
+msgstr "Варіанти алгоритмів різниці"
+
+msgid "produce the smallest possible diff"
+msgstr "створювати найменшу можливу різницю"
+
+msgid "ignore whitespace when comparing lines"
+msgstr "ігнорувати пробіли при порівнянні рядків"
+
+msgid "ignore changes in amount of whitespace"
+msgstr "ігнорувати зміни кількості пробілів"
+
+msgid "ignore changes in whitespace at EOL"
+msgstr "ігнорувати зміни пробілів у EOL"
+
+msgid "ignore carrier-return at the end of line"
+msgstr "ігнорувати повернення каретки в кінці рядка"
+
+msgid "ignore changes whose lines are all blank"
+msgstr "ігнорувати зміни, всі рядки яких порожні"
+
+msgid "<regex>"
+msgstr "<регвир>"
+
+msgid "ignore changes whose all lines match <regex>"
+msgstr "ігнорувати зміни, всі рядки яких збігаються з <регвир>"
+
+msgid "heuristic to shift diff hunk boundaries for easy reading"
+msgstr "евристичне визначення зміщення меж шматка різниці для зручного читання"
+
+msgid "generate diff using the \"patience diff\" algorithm"
+msgstr "згенерувати різницю за алгоритмом \"patience diff\""
+
+msgid "generate diff using the \"histogram diff\" algorithm"
+msgstr "згенерувати різницю за алгоритмом \"histogram diff\""
+
+msgid "<algorithm>"
+msgstr "<алгоритм>"
+
+msgid "choose a diff algorithm"
+msgstr "вибрати алгоритм різниці"
+
+msgid "<text>"
+msgstr "<текст>"
+
+msgid "generate diff using the \"anchored diff\" algorithm"
+msgstr "згенерувати різницю за алгоритмом \"anchored diff\""
+
+msgid "<mode>"
+msgstr "<режим>"
+
+msgid "show word diff, using <mode> to delimit changed words"
+msgstr ""
+"показати різницю по словам, використовуючи <режим> для відокремлення "
+"змінених слів"
+
+msgid "use <regex> to decide what a word is"
+msgstr "скористайтесь <регвир>, щоб визначити, що це за слово"
+
+msgid "equivalent to --word-diff=color --word-diff-regex=<regex>"
+msgstr "еквівалентно --word-diff=color --word-diff-regex=<регвир>"
+
+msgid "moved lines of code are colored differently"
+msgstr "переміщені рядки коду мають інший колір"
+
+msgid "how white spaces are ignored in --color-moved"
+msgstr "як ігноруються пробіли в --color-moved"
+
+msgid "Other diff options"
+msgstr "Інші опції різниці"
+
+msgid "when run from subdir, exclude changes outside and show relative paths"
+msgstr ""
+"при запуску з піддиректорії не враховувати зміни ззовні та показувати "
+"відносні шляхи"
+
+msgid "treat all files as text"
+msgstr "обробляти всі файли як текстові"
+
+msgid "swap two inputs, reverse the diff"
+msgstr "поміняти місцями два вводи, змінити різницю на протилежну"
+
+msgid "exit with 1 if there were differences, 0 otherwise"
+msgstr ""
+"завершити виконання з кодом 1, якщо були різниці, або з кодом 0 в іншому "
+"випадку"
+
+msgid "disable all output of the program"
+msgstr "вимкнути весь вивід програми"
+
+msgid "allow an external diff helper to be executed"
+msgstr "дозволити виконання зовнішнього помічника різниці"
+
+msgid "run external text conversion filters when comparing binary files"
+msgstr ""
+"запускати зовнішні фільтри конвертації тексту під час порівняння бінарних "
+"файлів"
+
+msgid "<when>"
+msgstr "<коли>"
+
+msgid "ignore changes to submodules in the diff generation"
+msgstr "ігнорувати зміни підмодулів у генерації різниці"
+
+msgid "<format>"
+msgstr "<формат>"
+
+msgid "specify how differences in submodules are shown"
+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 "обробляти \"git add -N\" записи як дійсні в індексі"
+
+msgid "<string>"
+msgstr "<строка>"
+
+msgid ""
+"look for differences that change the number of occurrences of the specified "
+"string"
+msgstr "шукати різниці, які змінюють кількість входжень вказаного рядка"
+
+msgid ""
+"look for differences that change the number of occurrences of the specified "
+"regex"
+msgstr "шукати різниці, які змінюють кількість входжень вказаного регвиру"
+
+msgid "show all changes in the changeset with -S or -G"
+msgstr "показати всі зміни у змінному наборі з -S або -G"
+
+msgid "treat <string> in -S as extended POSIX regular expression"
+msgstr "обробляти <рядок> у -S як розширений POSIX регулярний вираз"
+
+msgid "control the order in which files appear in the output"
+msgstr "керувати порядком, у якому файли зʼявляються у виводі"
+
+msgid "<path>"
+msgstr "<шлях>"
+
+msgid "show the change in the specified path first"
+msgstr "спочатку показати зміну для зазначеного шляху"
+
+msgid "skip the output to the specified path"
+msgstr "пропустити вивід для зазначеного шляху"
+
+msgid "<object-id>"
+msgstr "<id-обʼєкта>"
+
+msgid ""
+"look for differences that change the number of occurrences of the specified "
+"object"
+msgstr "шукати різниці, які змінюють кількість входжень вказаного обʼєкта"
+
+msgid "[(A|C|D|M|R|T|U|X|B)...[*]]"
+msgstr "[(A|C|D|M|R|T|U|X|B)...[*]]"
+
+msgid "select files by diff type"
+msgstr "вибрати файли за типом різниці"
+
+msgid "<file>"
+msgstr "<файл>"
+
+msgid "output to a specific file"
+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 "Виявлення неточного перейменування"
+
+#, c-format
+msgid "No such path '%s' in the diff"
+msgstr "Немає такого шляху \"%s\" у різниці"
+
+#, c-format
+msgid "pathspec '%s' did not match any file(s) known to git"
+msgstr "визначник шляху \"%s\" не збігається з жодним файлом, відомим git"
+
+#, c-format
+msgid "unrecognized pattern: '%s'"
+msgstr "нерозпізнаний шаблон: \"%s\""
+
+#, c-format
+msgid "unrecognized negative pattern: '%s'"
+msgstr "нерозпізнаний негативний шаблон: \"%s\""
+
+#, c-format
+msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
+msgstr ""
+"ваш файл розрідженого переходу може мати певні проблеми: шаблон \"%s\" "
+"повторюється"
+
+msgid "disabling cone pattern matching"
+msgstr "вимкнення зіставлення шаблону конуса"
+
+#, c-format
+msgid "cannot use %s as an exclude file"
+msgstr "неможливо використовувати %s як файл виключення"
+
+msgid "failed to get kernel name and information"
+msgstr "не вдалося отримати назву та інформацію про ядро"
+
+msgid "untracked cache is disabled on this system or location"
+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"
+msgstr "пошкоджено індексний файл у сховищі %s"
+
+#, c-format
+msgid "could not create directories for %s"
+msgstr "не вдалося створити директорії для %s"
+
+#, c-format
+msgid "could not migrate git directory from '%s' to '%s'"
+msgstr "не вдалося перенести git директорію з \"%s\" до \"%s\""
+
+#, c-format
+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 "не вдалося відредагувати \"%s\""
+
+msgid "Filtering content"
+msgstr "Фільтрація вмісту"
+
+#, c-format
+msgid "could not stat file '%s'"
+msgstr "не вдалося виконати stat для %s"
+
+#, c-format
+msgid "bad git namespace path \"%s\""
+msgstr "невірний шлях до простору імен git \"%s\""
+
+#, c-format
+msgid "too many args to run %s"
+msgstr "забагато аргументів для запуску %s"
+
+msgid "git fetch-pack: expected shallow list"
+msgstr "git fetch-pack: очікувався неглибокий список"
+
+msgid "git fetch-pack: expected a flush packet after shallow list"
+msgstr "git fetch-pack: очікувалось flush пакет після неглибокого списку"
+
+msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
+msgstr "git fetch-pack: очікувалось ACK/NAK, отримано flush пакет"
+
+#, c-format
+msgid "git fetch-pack: expected ACK/NAK, got '%s'"
+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 "неприпустимий shallow рядок: %s"
+
+#, c-format
+msgid "invalid unshallow line: %s"
+msgstr "неприпустимий unshallow рядок: %s"
+
+#, c-format
+msgid "object not found: %s"
+msgstr "обʼєкт не знайдено: %s"
+
+#, c-format
+msgid "error in object: %s"
+msgstr "помилка в обʼєкті: %s"
+
+#, c-format
+msgid "no shallow found: %s"
+msgstr "не знайдено неглибоких: %s"
+
+#, c-format
+msgid "expected shallow/unshallow, got %s"
+msgstr "очікувалось shallow/unshallow, отримано %s"
+
+#, c-format
+msgid "got %s %d %s"
+msgstr "отримано %s %d %s"
+
+#, c-format
+msgid "invalid commit %s"
+msgstr "неприпустимий коміт %s"
+
+msgid "giving up"
+msgstr "здаюся"
+
+msgid "done"
+msgstr "готово"
+
+#, c-format
+msgid "got %s (%d) %s"
+msgstr "отримано %s (%d) %s"
+
+#, c-format
+msgid "Marking %s as complete"
+msgstr "Позначення %s як завершеного"
+
+#, c-format
+msgid "already have %s (%s)"
+msgstr "вже є %s (%s)"
+
+msgid "fetch-pack: unable to fork off sideband demultiplexer"
+msgstr "fetch-pack: не вдалося розгалужити sideband demultiplexer"
+
+msgid "protocol error: bad pack header"
+msgstr "помилка протоколу: невірний заголовок пакунка"
+
+#, c-format
+msgid "fetch-pack: unable to fork off %s"
+msgstr "fetch-pack: не вдалося розгалужити %s"
+
+msgid "fetch-pack: invalid index-pack output"
+msgstr "fetch-pack: неприпустиме виведення індексного пакунка"
+
+#, c-format
+msgid "%s failed"
+msgstr "%s завершився невдало"
+
+msgid "error in sideband demultiplexer"
+msgstr "помилка в sideband demultiplexer"
+
+#, c-format
+msgid "Server version is %.*s"
+msgstr "Версія сервера %.*s"
+
+#, c-format
+msgid "Server supports %s"
+msgstr "Сервер підтримує %s"
+
+msgid "Server does not support shallow clients"
+msgstr "Сервер не підтримує неглибоких клієнтів"
+
+msgid "Server does not support --shallow-since"
+msgstr "Сервер не підтримує параметр --shallow-since"
+
+msgid "Server does not support --shallow-exclude"
+msgstr "Сервер не підтримує параметр --shallow-exclude"
+
+msgid "Server does not support --deepen"
+msgstr "Сервер не підтримує параметр --deepen"
+
+msgid "Server does not support this repository's object format"
+msgstr "Сервер не підтримує формат об’єктів цього сховища"
+
+msgid "no common commits"
+msgstr "немає спільних комітів"
+
+msgid "git fetch-pack: fetch failed."
+msgstr "git fetch-pack: помилка отримання."
+
+#, c-format
+msgid "mismatched algorithms: client %s; server %s"
+msgstr "невідповідність алгоритмів: клієнт %s; сервер %s"
+
+#, c-format
+msgid "the server does not support algorithm '%s'"
+msgstr "сервер не підтримує алгоритм \"%s\""
+
+msgid "Server does not support shallow requests"
+msgstr "Сервер не підтримує неглибокі запити"
+
+msgid "unable to write request to remote"
+msgstr "не вдалося записати запит до віддаленого сховища"
+
+#, c-format
+msgid "expected '%s', received '%s'"
+msgstr "очікувалось \"%s\", отримано \"%s\""
+
+#, c-format
+msgid "expected '%s'"
+msgstr "очікувалось \"%s\""
+
+#, c-format
+msgid "unexpected acknowledgment line: '%s'"
+msgstr "несподіваний рядок підтвердження: \"%s\""
+
+#, c-format
+msgid "error processing acks: %d"
+msgstr "помилка при обробці підтверджень: %d"
+
+#. TRANSLATORS: The parameter will be 'ready', a protocol
+#. keyword.
+#.
+
+#, c-format
+msgid "expected packfile to be sent after '%s'"
+msgstr "очікувалось надсилання файла пакунка після \"%s\""
+
+#. TRANSLATORS: The parameter will be 'ready', a protocol
+#. keyword.
+#.
+
+#, c-format
+msgid "expected no other sections to be sent after no '%s'"
+msgstr "не очікувалось надсилання жодної секції для статусу не \"%s\""
+
+#, c-format
+msgid "error processing shallow info: %d"
+msgstr "помилка при обробці неглибокої інформації: %d"
+
+#, c-format
+msgid "expected wanted-ref, got '%s'"
+msgstr "очікувалось wanted-ref, отримано \"%s\""
+
+#, c-format
+msgid "unexpected wanted-ref: '%s'"
+msgstr "несподіване запитуване посилання: \"%s\""
+
+#, c-format
+msgid "error processing wanted refs: %d"
+msgstr "помилка під час обробки запитуваних посилань: %d"
+
+msgid "git fetch-pack: expected response end packet"
+msgstr "git fetch-pack: очікувався response end пакет"
+
+msgid "no matching remote head"
+msgstr "немає відповідного віддаленого head"
+
+msgid "unexpected 'ready' from remote"
+msgstr "несподіване \"ready\" з віддаленого призначення"
+
+#, c-format
+msgid "no such remote ref %s"
+msgstr "немає такого віддаленого посилання %s"
+
+#, c-format
+msgid "Server does not allow request for unadvertised object %s"
+msgstr "Сервер забороняє запити до неоголошених обʼєктів %s"
+
+#, c-format
+msgid "fsmonitor_ipc__send_query: invalid path '%s'"
+msgstr "fsmonitor_ipc__send_query: неприпустимий шлях \"%s\""
+
+#, c-format
+msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
+msgstr "fsmonitor_ipc__send_query: невизначена помилка на \"%s\""
+
+msgid "fsmonitor--daemon is not running"
+msgstr "fsmonitor--daemon не запущено"
+
+#, c-format
+msgid "could not send '%s' command to fsmonitor--daemon"
+msgstr "не вдалося відправити команду \"%s\" до fsmonitor--daemon"
+
+#, c-format
+msgid "bare repository '%s' is incompatible with fsmonitor"
+msgstr "порожнє сховище \"%s\" несумісне з fsmonitor"
+
+#, c-format
+msgid "repository '%s' is incompatible with fsmonitor due to errors"
+msgstr "сховище \"%s\" несумісне з fsmonitor через помилки"
+
+#, c-format
+msgid "remote repository '%s' is incompatible with fsmonitor"
+msgstr "віддалене сховище \"%s\" несумісне з fsmonitor"
+
+#, c-format
+msgid "virtual repository '%s' is incompatible with fsmonitor"
+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"
+"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
+"bare]\n"
+"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
+"           [--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"
+"concept guides. See 'git help <command>' or 'git help <concept>'\n"
+"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 "непідтримуваний тип виводу команд \"%s\""
+
+#, c-format
+msgid "no directory given for '%s' option\n"
+msgstr "не вказано директорію для \"%s\" опціі\n"
+
+#, c-format
+msgid "no namespace given for --namespace\n"
+msgstr "не вказано простір імен для --namespace\n"
+
+#, c-format
+msgid "-c expects a configuration string\n"
+msgstr "-c очікує на рядок конфігурації\n"
+
+#, c-format
+msgid "no config key given for --config-env\n"
+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 "невідома опція: %s\n"
+
+#, c-format
+msgid "while expanding alias '%s': '%s'"
+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 "порожній псевдонім для %s"
+
+#, c-format
+msgid "recursive alias: %s"
+msgstr "рекурсивний псевдонім: %s"
+
+msgid "write failure on standard output"
+msgstr "помилка запису в стандартний вивід"
+
+msgid "unknown write failure on standard output"
+msgstr "невідома помилка запису в стандартний вивід"
+
+msgid "close failed on standard output"
+msgstr "не вдалося закрити стандартний вивід"
+
+#, c-format
+msgid "alias loop detected: expansion of '%s' does not terminate:%s"
+msgstr "виявлено цикл псевдонімів: розширення \"%s\" не припиняє:%s"
+
+#, c-format
+msgid "cannot handle %s as a builtin"
+msgstr "неможливо обробити %s як вбудовану команду"
+
+#, c-format
+msgid ""
+"usage: %s\n"
+"\n"
+msgstr "використання: %s\n"
+
+#, c-format
+msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
+msgstr "не вдалося розширити псевдонім \"%s\"; \"%s\" не є командою git\n"
+
+#, c-format
+msgid "failed to run command '%s': %s\n"
+msgstr "не вдалося виконати команду \"%s\": %s\n"
+
+msgid "could not create temporary file"
+msgstr "не вдалося створити тимчасовий файл"
+
+#, c-format
+msgid "failed writing detached signature to '%s'"
+msgstr "не вдалося записати відʼєднаний підпис до \"%s\""
+
+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 "файл скасування підпису ssh налаштовано, але не знайдено: %s"
+
+#, c-format
+msgid "bad/incompatible signature '%s'"
+msgstr "невірний/несумісний підпис \"%s\""
+
+#, c-format
+msgid "failed to get the ssh fingerprint for key '%s'"
+msgstr "не вдалося отримати ssh відбиток для ключа \"%s\""
+
+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 "gpg.ssh.defaultKeyCommand завершився невдало: %s %s"
+
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg не вдалося підписати дані:\n"
+"%s"
+
+msgid "user.signingKey needs to be set for ssh signing"
+msgstr "user.signingKey має бути налаштований для ssh підписання"
+
+#, c-format
+msgid "failed writing ssh signing key to '%s'"
+msgstr "не вдалося записати ssh ключ підпису до \"%s\""
+
+#, c-format
+msgid "failed writing ssh signing key buffer to '%s'"
+msgstr "не вдалося записати буфер ssh ключа підпису в \"%s\""
+
+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 "не вдалося прочитати буфер даних ssh підписання з \"%s\""
+
+#, c-format
+msgid "ignored invalid color '%.*s' in log.graphColors"
+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"
+msgstr "\"%s\": не вдалося прочитати %s"
+
+#, c-format
+msgid "'%s': short read"
+msgstr "\"%s\": помилка считування"
+
+msgid "start a working area (see also: git help tutorial)"
+msgstr "запустити робочу область (дивіться також: git help tutorial)"
+
+msgid "work on the current change (see also: git help everyday)"
+msgstr "працювати над поточними змінами (дивіться також: git help everyday)"
+
+msgid "examine the history and state (see also: git help revisions)"
+msgstr "переглянути історію та стан (дивіться також: git help revisions)"
+
+msgid "grow, mark and tweak your common history"
+msgstr "розвивати, позначати та підправляти вашу спільну історію"
+
+msgid "collaborate (see also: git help workflows)"
+msgstr "співпрацювати (дивіться також: git help workflows)"
+
+msgid "Main Porcelain Commands"
+msgstr "Основні високорівневі команди"
+
+msgid "Ancillary Commands / Manipulators"
+msgstr "Допоміжні команди / Маніпулятори"
+
+msgid "Ancillary Commands / Interrogators"
+msgstr "Допоміжні команди / Допитувачі"
+
+msgid "Interacting with Others"
+msgstr "Взаємодія з іншими"
+
+msgid "Low-level Commands / Manipulators"
+msgstr "Низькорівневі команди / Маніпулятори"
+
+msgid "Low-level Commands / Interrogators"
+msgstr "Низькорівневі команди / Допитувачі"
+
+msgid "Low-level Commands / Syncing Repositories"
+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\""
+
+msgid "git commands available from elsewhere on your $PATH"
+msgstr "команди git доступні з будь-якого місця на вашому $PATH"
+
+msgid "These are common Git commands used in various situations:"
+msgstr "Це загальні команди Git, які використовуються в різних ситуаціях:"
+
+msgid "The Git concept guides are:"
+msgstr "Посібники з понять Git:"
+
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Інтерфейси користувача для сховищ, команд та файлів:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Формати файлів, протоколи та інші інтерфейси розробника:"
+
+msgid "External commands"
+msgstr "Зовнішні команди"
+
+msgid "Command aliases"
+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 "git: \"%s\" не є командою git. Дивітья git --help."
+
+msgid "Uh oh. Your system reports no Git commands at all."
+msgstr "Ой-ой. Ваша система повідомляє про повну відсутність Git команд."
+
+#, c-format
+msgid "WARNING: You called a Git command named '%s', which does not exist."
+msgstr "ПОПЕРЕДЖЕННЯ: Ви викликали Git команду \"%s\", якої не існує."
+
+#, c-format
+msgid "Continuing under the assumption that you meant '%s'."
+msgstr "Продовжую, припускаючи, що ви мали на увазі \"%s\"."
+
+#, c-format
+msgid "Run '%s' instead [y/N]? "
+msgstr "Запустити натомість \"%s\" [y/N]? "
+
+#, c-format
+msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
+msgstr "Продовжую через %0.1f секунд, припускаючи, що ви мали на увазі \"%s\"."
+
+msgid ""
+"\n"
+"The most similar command is"
+msgid_plural ""
+"\n"
+"The most similar commands are"
+msgstr[0] ""
+"\n"
+"Найбільш схожою командою є"
+msgstr[1] ""
+"\n"
+"Найбільш схожими командами є"
+msgstr[2] ""
+"\n"
+"Найбільш схожими командами є"
+
+msgid "git version [--build-options]"
+msgstr "git версія [--build-options]"
+
+#, c-format
+msgid "%s: %s - %s"
+msgstr "%s: %s - %s"
+
+msgid ""
+"\n"
+"Did you mean this?"
+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 "аргумент до --packfile має бути коректним хешем (отримано \"%s\")"
+
+msgid "not a git repository"
+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 "Контроль делегування не підтримується з cURL < 7.22.0"
+
+msgid "Public key pinning not supported with cURL < 7.39.0"
+msgstr "Закріплення відкритих ключів не підтримується з cURL < 7.39.0"
+
+msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
+msgstr "CURLSSLOPT_NO_REVOKE не підтримується з cURL < 7.44.0"
+
+#, c-format
+msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
+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 "Не вдалося встановити SSL обробник в \"%s\": вже встановлено"
+
+#, c-format
+msgid ""
+"unable to update url base from redirection:\n"
+"  asked for: %s\n"
+"   redirect: %s"
+msgstr ""
+"не вдалося оновити базу url з перенаправлення:\n"
+"  запитували: %s\n"
+"   перенаправлення: %s"
+
+msgid "Author identity unknown\n"
+msgstr "Особистість автора невідома\n"
+
+msgid "Committer identity unknown\n"
+msgstr "Особистість комітера невідома\n"
+
+msgid ""
+"\n"
+"*** Please tell me who you are.\n"
+"\n"
+"Run\n"
+"\n"
+"  git config --global user.email \"you@example.com\"\n"
+"  git config --global user.name \"Your Name\"\n"
+"\n"
+"to set your account's default identity.\n"
+"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 "не вказана адреса електронної пошти і автоматичне визначення вимкнено"
+
+#, c-format
+msgid "unable to auto-detect email address (got '%s')"
+msgstr ""
+"не вдалося автоматично визначити адресу електронної пошти (отримано \"%s\")"
+
+msgid "no name was given and auto-detection is disabled"
+msgstr "імʼя не вказано і автоматичне визначення вимкнено"
+
+#, c-format
+msgid "unable to auto-detect name (got '%s')"
+msgstr "не вдалося автоматично визначити назву (отримано \"%s\")"
+
+#, c-format
+msgid "empty ident name (for <%s>) not allowed"
+msgstr "порожнє імʼя особистості (для <%s>) заборонено"
+
+#, c-format
+msgid "name consists only of disallowed characters: %s"
+msgstr "імʼя складається лише з заборонених символів: %s"
+
+msgid "expected 'tree:<depth>'"
+msgstr "очікувалось \"tree:<глибина>\""
+
+msgid "sparse:path filters support has been dropped"
+msgstr "підтримку фільтрів sparse:path було припинено"
+
+#, c-format
+msgid "'%s' for 'object:type=<type>' is not a valid object type"
+msgstr "\"%s\" для \"object:type=<type>\" не є припустимим типом обʼєкта"
+
+#, c-format
+msgid "invalid filter-spec '%s'"
+msgstr "неприпустимий визначник фільтра \"%s\""
+
+#, c-format
+msgid "must escape char in sub-filter-spec: '%c'"
+msgstr "необхідно екранувати символ у sub-filter-spec: \"%c\""
+
+msgid "expected something after combine:"
+msgstr "щоcь очікувалось після комбінування:"
+
+msgid "multiple filter-specs cannot be combined"
+msgstr "не можна комбінувати кілька визначників фільтра"
+
+msgid "unable to upgrade repository format to support partial clone"
+msgstr "не вдалося оновити формат сховища для підтримки часткового клонування"
+
+msgid "args"
+msgstr "аргументи"
+
+msgid "object filtering"
+msgstr "фільтрація обʼєктів"
+
+#, c-format
+msgid "unable to access sparse blob in '%s'"
+msgstr "не вдалося отримати доступ до розрідженого blob в \"%s\""
+
+#, c-format
+msgid "unable to parse sparse filter data in %s"
+msgstr "не вдалося розібрати дані розрідженого фільтра в %s"
+
+#, c-format
+msgid "entry '%s' in tree %s has tree mode, but is not a tree"
+msgstr "запис \"%s\" у дереві %s має режим tree, але не є деревом"
+
+#, c-format
+msgid "entry '%s' in tree %s has blob mode, but is not a blob"
+msgstr "запис \"%s\" у дереві %s має режим blob, але не є blob"
+
+#, c-format
+msgid "unable to load root tree for commit %s"
+msgstr "не вдалося завантажити кореневе дерево для коміту %s"
+
+#, c-format
+msgid ""
+"Unable to create '%s.lock': %s.\n"
+"\n"
+"Another git process seems to be running in this repository, e.g.\n"
+"an editor opened by 'git commit'. Please make sure all processes\n"
+"are terminated then try again. If it still fails, a git process\n"
+"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"
+msgstr "Не вдалося створити \"%s.lock\": %s"
+
+#, c-format
+msgid "unexpected line: '%s'"
+msgstr "неочікуваний рядок: \"%s\""
+
+msgid "expected flush after ls-refs arguments"
+msgstr "очікувався flush після ls-refs аргументів"
+
+msgid "quoted CRLF detected"
+msgstr "виявлено цитований CRLF"
+
+#, c-format
+msgid "Failed to merge submodule %s (not checked out)"
+msgstr "Не вдалося обʼєднати підмодуль %s (не активне)"
+
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Не вдалося злити підмодуль %s (немає бази злиття)"
+
+#, c-format
+msgid "Failed to merge submodule %s (commits not present)"
+msgstr "Не вдалося злити підмодуль %s (відсутні коміти)"
+
+#, c-format
+msgid "Failed to merge submodule %s (commits don't follow merge-base)"
+msgstr "Не вдалося злити підмодуль %s (коміти не відповідають базі)"
+
+#, c-format
+msgid "Note: Fast-forwarding submodule %s to %s"
+msgstr "Примітка: перемотування підмодуля %s вперед до %s"
+
+#, c-format
+msgid "Failed to merge submodule %s"
+msgstr "Не вдалося злити підмодуль %s"
+
+#, c-format
+msgid ""
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
+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 "Не вдалося виконати внутрішнє злиття"
+
+#, c-format
+msgid "Unable to add %s to database"
+msgstr "Не вдалося додати %s до бази даних"
+
+#, c-format
+msgid "Auto-merging %s"
+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 ""
+"CONFLICT (directory rename split): Unclear where to rename %s to; it was "
+"renamed to multiple other directories, with no destination getting a "
+"majority of the files."
+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 ""
+"CONFLICT (rename involved in collision): rename of %s -> %s has content "
+"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"
+msgstr "неможливо прочитати обʼєкт %s"
+
+#, c-format
+msgid "object %s is not a blob"
+msgstr "обʼєкт %s не є blob"
+
+#, c-format
+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 "вміст"
+
+msgid "add/add"
+msgstr "додано/додано"
+
+msgid "submodule"
+msgstr "підмодуль"
+
+#, c-format
+msgid "CONFLICT (%s): Merge conflict in %s"
+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
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#. - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - перейдіть до підмодуля (%s), щоб або злити коміт %s\n"
+"   або оновитись до існуючого коміту, в якому ці зміни вже злиті\n"
+
+#, c-format
+msgid ""
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
+msgstr ""
+"Рекурсивне злиття з підмодулями наразі підтримує лише тривіальні випадки.\n"
+"Будь ласка, обробіть злиття кожного конфліктного підмодуля вручну.\n"
+"Це можна зробити за допомогою наступних кроків:\n"
+"%s - поверніться до суперпроекту і виконайте:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   щоб записати вищезгадане злиття або оновлення\n"
+"- розвʼяжіть будь-які інші конфлікти в суперпроекті\n"
+"- зробіть коміт підсумкового індекса в суперпроекті\n"
+
+#. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
+#. base, and 2-3) the trees for the two trees we're merging.
+#.
+
+#, c-format
+msgid "collecting merge info failed for trees %s, %s, %s"
+msgstr "збирання інформації про злиття не вдалося для дерев %s, %s, %s"
+
+msgid "(bad commit)\n"
+msgstr "(невірний коміт)\n"
+
+#, c-format
+msgid "add_cacheinfo failed for path '%s'; merge aborting."
+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"
+msgstr "не вдалося створити шлях \"%s\"%s"
+
+#, c-format
+msgid "Removing %s to make room for subdirectory\n"
+msgstr "Видалення %s, щоб звільнити місце для піддиректорії\n"
+
+msgid ": perhaps a D/F conflict?"
+msgstr ": можливо, D/F конфлікт?"
+
+#, c-format
+msgid "refusing to lose untracked file at '%s'"
+msgstr "відмовлено у втраті невідстежуваного файла \"%s\""
+
+#, c-format
+msgid "blob expected for %s '%s'"
+msgstr "blob очікується для %s \"%s\""
+
+#, c-format
+msgid "failed to open '%s': %s"
+msgstr "не вдалося відкрити \"%s\": %s"
+
+#, c-format
+msgid "failed to symlink '%s': %s"
+msgstr "не вдалося зробити символьне посилання \"%s\": %s"
+
+#, c-format
+msgid "do not know what to do with %06o %s '%s'"
+msgstr "не знаю, що робити з %06o %s \"%s\""
+
+#, c-format
+msgid "Fast-forwarding submodule %s to the following commit:"
+msgstr "Перемотування підмодуля %s вперед до наступного коміту:"
+
+#, c-format
+msgid "Fast-forwarding submodule %s"
+msgstr "Перемотування підмодуля %s вперед"
+
+#, c-format
+msgid "Failed to merge submodule %s (merge following commits not found)"
+msgstr "Не вдалося злити підмодуль %s (злиття наступних комітів не знайдено)"
+
+#, c-format
+msgid "Failed to merge submodule %s (not fast-forward)"
+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"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"який прийме цю пропозицію.\n"
+
+#, c-format
+msgid "Failed to merge submodule %s (multiple merges found)"
+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 "перейменувати"
+
+msgid "renamed"
+msgstr "перейменовано"
+
+#, c-format
+msgid "Refusing to lose dirty file at %s"
+msgstr "Відмовлено у втраті брудного файла %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 "%s є директорією в %s, натомість додаємо як %s"
+
+#, c-format
+msgid "Refusing to lose untracked file at %s; adding as %s instead"
+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 " (залишилося нерозвʼязаним)"
+
+#, 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 ""
+"CONFLICT (directory rename split): Unclear where to place %s because "
+"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 "змінити"
+
+msgid "modified"
+msgstr "змінено"
+
+#, c-format
+msgid "Skipped %s (merged same as existing)"
+msgstr "Пропущено %s (злите - те саме, що й існуюче)"
+
+#, c-format
+msgid "Adding as %s instead"
+msgstr "Додавання як %s замість цього"
+
+#, c-format
+msgid "Removing %s"
+msgstr "Видалення %s"
+
+msgid "file/directory"
+msgstr "файл/директорія"
+
+msgid "directory/file"
+msgstr "директорія/файл"
+
+#, c-format
+msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
+msgstr "КОНФЛІКТ (%s): в %s існує директорія з іменем %s. Додавання %s як %s"
+
+#, c-format
+msgid "Adding %s"
+msgstr "Додавання %s"
+
+#, c-format
+msgid "CONFLICT (add/add): Merge conflict in %s"
+msgstr "КОНФЛІКТ (додано/додано): Конфлікт злиття у %s"
+
+#, c-format
+msgid "merging of trees %s and %s failed"
+msgstr "не вдалося злити дерева %s та %s"
+
+msgid "Merging:"
+msgstr "Злиття:"
+
+#, c-format
+msgid "found %u common ancestor:"
+msgid_plural "found %u common ancestors:"
+msgstr[0] "знайшли %u спільного предка:"
+msgstr[1] "знайшли %u спільних предків:"
+msgstr[2] "знайшли %u спільних предків:"
+
+msgid "merge returned no commit"
+msgstr "злиття не повернуло коміт"
+
+#, c-format
+msgid "Could not parse object '%s'"
+msgstr "Не вдалося розібрати обʼєкт \"%s\""
+
+msgid "failed to read the cache"
+msgstr "не вдалося прочитати кеш"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "multi-pack-index OID fanout має невірний розмір"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "multi-pack-index файл %s занадто малий"
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "multi-pack-index підпис 0x%08x не збігається з підписом 0x%08x"
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "multi-pack-index версія %d не розпізнана"
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "версія хешу multi-pack-index %u не збігається з версією %u"
+
+msgid "multi-pack-index missing required pack-name chunk"
+msgstr "multi-pack-index недостає необхідного фрагмента імені пакунка"
+
+msgid "multi-pack-index missing required OID fanout chunk"
+msgstr "multi-pack-index недостає необхідного OID fanout фрагмента"
+
+msgid "multi-pack-index missing required OID lookup chunk"
+msgstr "multi-pack-index недостає необхідного OID lookup фрагмента"
+
+msgid "multi-pack-index missing required object offsets chunk"
+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 "невірний 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'"
+msgstr "не вдалося додати packfile \"%s\""
+
+#, c-format
+msgid "failed to open pack-index '%s'"
+msgstr "не вдалося відкрити pack-index \"%s\""
+
+#, c-format
+msgid "failed to locate object %d in packfile"
+msgstr "не вдалося знайти обʼєкт %d у файлі пакунка"
+
+msgid "cannot store reverse index file"
+msgstr "неможливо зберегти файл зворотнього індексу"
+
+#, c-format
+msgid "could not parse line: %s"
+msgstr "не вдалося розібрати рядок: %s"
+
+#, c-format
+msgid "malformed line: %s"
+msgstr "невірно сформований рядок: %s"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"ігнорування існуючого multi-pack-index; невідповідність контрольних сум"
+
+msgid "could not load pack"
+msgstr "не вдалося завантажити пакет"
+
+#, c-format
+msgid "could not open index for %s"
+msgstr "не вдалося відкрити індекс для %s"
+
+msgid "Adding packfiles to multi-pack-index"
+msgstr "Додавання пакунків до multi-pack-index"
+
+#, c-format
+msgid "unknown preferred pack: '%s'"
+msgstr "невідомий бажаний пакунок: \"%s\""
+
+#, c-format
+msgid "cannot select preferred pack %s with no objects"
+msgstr "неможливо вибрати бажаний пакунок %s за відсутності об’єктів"
+
+#, c-format
+msgid "did not see pack-file %s to drop"
+msgstr "не побачив файл пакунка %s, який потрібно скинути"
+
+#, c-format
+msgid "preferred pack '%s' is expired"
+msgstr "у бажаного пакета \"%s\" закінчився термін дії"
+
+msgid "no pack files to index."
+msgstr "немає файлів пакунків для індексації."
+
+msgid "refusing to write multi-pack .bitmap without any objects"
+msgstr "відмовлено в записі мультіпакункового .bitmap без обʼєктів"
+
+msgid "could not write multi-pack bitmap"
+msgstr "не вдалося записати мультіпакунковий bitmap"
+
+msgid "could not write multi-pack-index"
+msgstr "не вдалося записати multi-pack-index"
+
+#, c-format
+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 "multi-pack-index файл існує, але його не вдалося розібрати"
+
+msgid "incorrect checksum"
+msgstr "невірна контрольна сума"
+
+msgid "Looking for referenced packfiles"
+msgstr "Пошук файлів пакунків, на які є посилання"
+
+#, c-format
+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 "midx не містить oid"
+
+msgid "Verifying OID order in multi-pack-index"
+msgstr "Перевірка OID послідовності в multi-pack-index"
+
+#, c-format
+msgid "oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"
+msgstr "невірна послідовність oid lookup: oid[%d] = %s >= %s = oid[%d]"
+
+msgid "Sorting objects by packfile"
+msgstr "Сортування обʼєктів за файлом пакунка"
+
+msgid "Verifying object offsets"
+msgstr "Перевірка зміщень обʼєкта"
+
+#, c-format
+msgid "failed to load pack entry for oid[%d] = %s"
+msgstr "не вдалося завантажити запис пакунка для oid[%d] = %s"
+
+#, c-format
+msgid "failed to load pack-index for packfile %s"
+msgstr "не вдалося завантажити індекс файла пакунка %s"
+
+#, c-format
+msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
+msgstr "невірне зміщення обʼєкта для oid[%d] = %s: %<PRIx64> != %<PRIx64>"
+
+msgid "Counting referenced objects"
+msgstr "Підрахунок обʼєктів, на які є посилання"
+
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Пошук і видалення файлів пакунків без посилань"
+
+msgid "could not start pack-objects"
+msgstr "не вдалося розпочати pack-objects"
+
+msgid "could not finish pack-objects"
+msgstr "не вдалося завершити pack-objects"
+
+#, c-format
+msgid "unable to create lazy_dir thread: %s"
+msgstr "не вдалося створити lazy_dir потік: %s"
+
+#, c-format
+msgid "unable to create lazy_name thread: %s"
+msgstr "не вдалося створити lazy_name потік: %s"
+
+#, c-format
+msgid "unable to join lazy_name thread: %s"
+msgstr "не вдалося приєднатися до lazy_name потоку: %s"
+
+#, c-format
+msgid ""
+"You have not concluded your previous notes merge (%s exists).\n"
+"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 "Ви не завершили злиття ваших нотаток (%s існує)."
+
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "Неможливо зробити коміт неініціалізованого/непосиланого дерева нотаток"
+
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Невірнe notes.rewriteMode значення: \"%s\""
+
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "Відмовлено в перезаписі нотаток у %s (за межами 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 "Невірне %s значення: \"%s\""
+
+#, c-format
+msgid "object directory %s does not exist; check .git/objects/info/alternates"
+msgstr "директорія об’єкта %s не існує; перевірте .git/objects/info/alternates"
+
+#, c-format
+msgid "unable to normalize alternate object path: %s"
+msgstr "не вдалося нормалізувати шлях запозиченого обʼєкта: %s"
+
+#, c-format
+msgid "%s: ignoring alternate object stores, nesting too deep"
+msgstr ""
+"%s: ігнорування місць збереження запозичених об’єктів, надто глибока "
+"вкладеність"
+
+msgid "unable to fdopen alternates lockfile"
+msgstr "не вдалося виконати fdopen для файла блокування запозичених обʼєктів"
+
+msgid "unable to read alternates file"
+msgstr "не вдалося прочитати файл запозичених обʼєктів"
+
+msgid "unable to move new alternates file into place"
+msgstr "не вдалося перемістити файл нових запозичених обʼєктів на місце"
+
+#, c-format
+msgid "path '%s' does not exist"
+msgstr "шлях \"%s\" не існує"
+
+#, c-format
+msgid "reference repository '%s' as a linked checkout is not supported yet."
+msgstr "посилання на сховище \"%s\" як повʼязане поки що не підтримується."
+
+#, c-format
+msgid "reference repository '%s' is not a local repository."
+msgstr "сховище посилання \"%s\" не є локальним сховищем."
+
+#, c-format
+msgid "reference repository '%s' is shallow"
+msgstr "сховище посилання \"%s\" є неглибоким"
+
+#, c-format
+msgid "reference repository '%s' is grafted"
+msgstr "сховище посилання \"%s\" прищеплено"
+
+#, c-format
+msgid "could not find object directory matching %s"
+msgstr "не вдалося знайти директорію обʼєктів, що відповідає %s"
+
+#, c-format
+msgid "invalid line while parsing alternate refs: %s"
+msgstr "неприпустимий рядок при розбиранні посилань запозичених обʼєктів: %s"
+
+#, c-format
+msgid "attempting to mmap %<PRIuMAX> over limit %<PRIuMAX>"
+msgstr "спроба виконати mmap %<PRIuMAX> за межею %<PRIuMAX>"
+
+#, c-format
+msgid "mmap failed%s"
+msgstr "операція mmap не вдалася%s"
+
+#, c-format
+msgid "object file %s is empty"
+msgstr "обʼєктний файл %s порожній"
+
+#, c-format
+msgid "corrupt loose object '%s'"
+msgstr "пошкоджено вільний обʼєкт \"%s\""
+
+#, c-format
+msgid "garbage at end of loose object '%s'"
+msgstr "непотріб в кінці вільного обʼєкта \"%s\""
+
+#, c-format
+msgid "unable to open loose object %s"
+msgstr "не вдалося відкрити вільний обʼєкт %s"
+
+#, c-format
+msgid "unable to parse %s header"
+msgstr "не вдалося розібрати заголовок %s"
+
+msgid "invalid object type"
+msgstr "неприпустимий тип обʼєкта"
+
+#, c-format
+msgid "unable to unpack %s header"
+msgstr "не вдалося розпакувати %s заголовок"
+
+#, c-format
+msgid "header for %s too long, exceeds %d bytes"
+msgstr "заголовок для %s занадто довгий, перевищує %d байт"
+
+#, c-format
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "вільний обʼєкт %s (що зберігається у %s) пошкоджено"
+
+#, c-format
+msgid "replacement %s not found for %s"
+msgstr "заміна %s не знайдена для %s"
+
+#, c-format
+msgid "packed object %s (stored in %s) is corrupt"
+msgstr "упакований обʼєкт %s (що зберігається у %s) пошкоджено"
+
+#, c-format
+msgid "unable to write file %s"
+msgstr "не вдалося записати файл %s"
+
+#, c-format
+msgid "unable to set permission to '%s'"
+msgstr "не вдалося встановити дозволи для \"%s\""
+
+msgid "error when closing loose object file"
+msgstr "помилка при закритті файла вільного об’єкта"
+
+#, c-format
+msgid "insufficient permission for adding an object to repository database %s"
+msgstr "недостатньо дозволу для додавання обʼєкта до бази даних сховища %s"
+
+msgid "unable to create temporary file"
+msgstr "не вдалося створити тимчасовий файл"
+
+msgid "unable to write loose object file"
+msgstr "не вдалося записати файл вільного об’єкта"
+
+#, c-format
+msgid "unable to deflate new object %s (%d)"
+msgstr "не вдалося запакувати новий обʼєкт %s (%d)"
+
+#, c-format
+msgid "deflateEnd on object %s failed (%d)"
+msgstr "операція deflateEnd на обʼєкті %s завершилася невдало (%d)"
+
+#, c-format
+msgid "confused by unstable object source data for %s"
+msgstr "збентежений нестабільними початковими даними обʼєкта для %s"
+
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "запис обʼєкта потока %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "не вдалося запакувати новий обʼєкт (%d) при передачі"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "операція deflateEnd на обʼєкті потоку завершилася невдало (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "не вдалося створити директорію %s"
+
+#, c-format
+msgid "cannot read object for %s"
+msgstr "неможливо прочитати обʼєкт для %s"
+
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "об’єкт не пройшов перевірку fsck: %s"
+
+msgid "refusing to create malformed object"
+msgstr "відмовлено в створенні невірно сформованого обʼєкта"
+
+#, c-format
+msgid "read error while indexing %s"
+msgstr "помилка считування при індексаціі %s"
+
+#, c-format
+msgid "short read while indexing %s"
+msgstr "помилка считування замалого вмісту при індексаціі %s"
+
+#, c-format
+msgid "%s: failed to insert into database"
+msgstr "%s: не вдалося внести до бази даних"
+
+#, c-format
+msgid "%s: unsupported file type"
+msgstr "%s: непідтримуваний тип файлу"
+
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr "%s не є допустимим \"%s\" обʼєктом"
+
+#, c-format
+msgid "unable to open %s"
+msgstr "не вдалося відкрити %s"
+
+#, c-format
+msgid "hash mismatch for %s (expected %s)"
+msgstr "невідповідність хешу для %s (очікувалось %s)"
+
+#, c-format
+msgid "unable to mmap %s"
+msgstr "не вдалося виконати mmap %s"
+
+#, c-format
+msgid "unable to unpack header of %s"
+msgstr "не вдалося розпакувати заголовок %s"
+
+#, c-format
+msgid "unable to parse header of %s"
+msgstr "не вдалося розібрати заголовок %s"
+
+#, c-format
+msgid "unable to unpack contents of %s"
+msgstr "не вдалося розпакувати вміст %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 [невірний обʼект]"
+
+#. TRANSLATORS: This is a line of ambiguous commit
+#. object output. E.g.:
+#. *
+#. "deadbeef commit 2021-01-01 - Some Commit Message"
+#.
+
+#, c-format
+msgid "%s commit %s - %s"
+msgstr "%s коміт %s - %s"
+
+#. TRANSLATORS: This is a line of ambiguous
+#. tag object output. E.g.:
+#. *
+#. "deadbeef tag 2022-01-01 - Some Tag Message"
+#. *
+#. The second argument is the YYYY-MM-DD found
+#. in the tag.
+#. *
+#. The third argument is the "tag" string
+#. from object.c.
+#.
+
+#, c-format
+msgid "%s tag %s - %s"
+msgstr "%s тег %s - %s"
+
+#. TRANSLATORS: This is a line of ambiguous
+#. tag object output where we couldn't parse
+#. the tag itself. E.g.:
+#. *
+#. "deadbeef [bad tag, could not parse it]"
+#.
+
+#, c-format
+msgid "%s [bad tag, could not parse it]"
+msgstr "%s [невірний тег, не вдалося розібрати]"
+
+#. TRANSLATORS: This is a line of ambiguous <type>
+#. object output. E.g. "deadbeef tree".
+#.
+
+#, c-format
+msgid "%s tree"
+msgstr "%s дерево"
+
+#. TRANSLATORS: This is a line of ambiguous <type>
+#. object output. E.g. "deadbeef blob".
+#.
+
+#, c-format
+msgid "%s blob"
+msgstr "%s blob"
+
+#, c-format
+msgid "short object ID %s is ambiguous"
+msgstr "короткий ідентифікатор обʼєкта %s неоднозначний"
+
+#. 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"
+"%s"
+msgstr ""
+"Кандидати такі:\n"
+"%s"
+
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+"  git switch -c $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"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"
+msgstr "лог для \"%.*s\" містить записи тільки до %s"
+
+#, c-format
+msgid "log for '%.*s' only has %d entries"
+msgstr "лог для \"%.*s\" містить лише %d записів"
+
+#, c-format
+msgid "path '%s' exists on disk, but not in '%.*s'"
+msgstr "шлях \"%s\" існує на диску, але не в \"%.*s\""
+
+#, c-format
+msgid ""
+"path '%s' exists, but not '%s'\n"
+"hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"
+msgstr ""
+"шлях \"%s\" існує, але не \"%s\"\n"
+"підказка: ви мали на увазі \"%.*s:%s\" або \"%.*s:./%s\"?"
+
+#, c-format
+msgid "path '%s' does not exist in '%.*s'"
+msgstr "шлях \"%s\" не існує в \"%.*s\""
+
+#, c-format
+msgid ""
+"path '%s' is in the index, but not at stage %d\n"
+"hint: Did you mean ':%d:%s'?"
+msgstr ""
+"шлях \"%s\" є в індексі, але відсутній на стадії %d\n"
+"підказка: ви мали на увазі \":%d:%s\"?"
+
+#, c-format
+msgid ""
+"path '%s' is in the index, but not '%s'\n"
+"hint: Did you mean ':%d:%s' aka ':%d:./%s'?"
+msgstr ""
+"шлях \"%s\" є в індексі, але не \"%s\"\n"
+"підказка: ви мали на увазі \"%d:%s\" або \"%d:./%s\"?"
+
+#, c-format
+msgid "path '%s' exists on disk, but not in the index"
+msgstr "шлях \"%s\" існує на диску, але відсутній в індексі"
+
+#, c-format
+msgid "path '%s' does not exist (neither on disk nor in the index)"
+msgstr "шлях \"%s\" не існує (ні на диску, ні в індексі)"
+
+msgid "relative path syntax can't be used outside working tree"
+msgstr ""
+"синтаксис відносного шляху не можна використовувати поза робочим деревом"
+
+#, c-format
+msgid "<object>:<path> required, only <object> '%s' given"
+msgstr "потрібно <обʼєкт>:<шлях>, надано лише <обʼєкт> \"%s\""
+
+#, c-format
+msgid "invalid object name '%.*s'."
+msgstr "неприпустима назва обʼєкта \"%.*s\"."
+
+#, c-format
+msgid "invalid object type \"%s\""
+msgstr "неприпустимий тип обʼєкту \"%s\""
+
+#, c-format
+msgid "object %s is a %s, not a %s"
+msgstr "обʼєкт %s є %s, а не %s"
+
+#, c-format
+msgid "object %s has unknown type id %d"
+msgstr "обʼєкт %s має невідомий тип ідентифікатора %d"
+
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "не вдалося розібрати обʼєкт: %s"
+
+#, c-format
+msgid "hash mismatch %s"
+msgstr "невідповідність хешу %s"
+
+msgid "trying to write commit not in index"
+msgstr "спроба записати коміт, якого немає в індексі"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "не вдалося завантажити bitmap індекс (пошкоджено?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "пошкоджений bitmap індекс (занадто малий)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "пошкоджений файл bitmap індексу (занадто малий)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "непідтримувана версія \"%d\" для файлу bitmap індексу"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"пошкоджений файл bitmap індексу (занадто короткий щоб умістити кеш хеша)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"пошкоджений файл bitmap індексу (занадто короткий, щоб вмістити таблицю "
+"пошуку)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "дубльований запис в bitmap індексі: \"%s\""
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "пошкоджений ewah bitmap: урізаний заголовок для запису %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "пошкоджений ewah bitmap: індекс коміту %u поза межами діапазону"
+
+msgid "corrupted bitmap pack index"
+msgstr "пошкоджений bitmap індекс пакунка"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "невірне XOR зміщення в bitmap індексі пакунка"
+
+msgid "cannot fstat bitmap file"
+msgstr "неможливо виконати fstat для bitmap файла"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "контрольна сума не збігається в MIDX і bitmap"
+
+msgid "multi-pack bitmap is missing required reverse index"
+msgstr "у мультіпакунковому bitmap відсутній необхідний зворотний індекс"
+
+#, c-format
+msgid "could not open pack %s"
+msgstr "не вдалося відкрити пакунок %s"
+
+#, c-format
+msgid "preferred pack (%s) is invalid"
+msgstr "бажаний пакунок (%s) є неприпустимим"
+
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "пошкоджена bitmap таблиця пошуку: триплетна позиція поза індексом"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr ""
+"пошкоджена bitmap таблиця пошуку: xor ланцюжок перевищує кількість записів"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr ""
+"пошкоджена bitmap таблиця пошуку: індекс коміту %u поза межами діапазону"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr "пошкоджений ewah bitmap: урізаний заголовок для bitmap коміту \"%s\""
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "обʼєкт \"%s\" не знайдено в типах bitmap"
+
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "обʼєкт \"%s\" не має унікального типу"
+
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "обʼєкт \"%s\": дійсний тип \"%s\", очікуваний: \"%s\""
+
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "обʼєкт не у bitmap: \"%s\""
+
+msgid "failed to load bitmap indexes"
+msgstr "не вдалося завантажити bitmap індекси"
+
+msgid "you must specify exactly one commit to test"
+msgstr "ви маєте вказати лишень один коміт для тестування"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "коміт \"%s\" не має індексованого bitmap"
+
+msgid "mismatch in bitmap results"
+msgstr "розбіжність в bitmap результатах"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "не вдалося знайти \"%s\" у пакунку \"%s\" зі зміщенням %<PRIuMAX>"
+
+#, c-format
+msgid "unable to get disk usage of '%s'"
+msgstr ""
+"не вдалося отримати дані про використання дискового простору для \"%s\""
+
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "bitmap файл \"%s\" має невірну контрольну суму"
+
+#, c-format
+msgid "mtimes file %s is too small"
+msgstr "mtimes файл %s занадто малий"
+
+#, c-format
+msgid "mtimes file %s has unknown signature"
+msgstr "mtimes файл %s має невідомий підпис"
+
+#, c-format
+msgid "mtimes file %s has unsupported version %<PRIu32>"
+msgstr "mtimes файл %s має непідтримувану версію %<PRIu32>"
+
+#, c-format
+msgid "mtimes file %s has unsupported hash id %<PRIu32>"
+msgstr "mtimes файл %s має непідтримуваний хеш-ідентифікатор %<PRIu32>"
+
+#, c-format
+msgid "mtimes file %s is corrupt"
+msgstr "mtimes файл %s пошкоджено"
+
+#, c-format
+msgid "reverse-index file %s is too small"
+msgstr "файл зворотного індексу %s занадто малий"
+
+#, c-format
+msgid "reverse-index file %s is corrupt"
+msgstr "файл зворотнього індексу %s пошкоджено"
+
+#, c-format
+msgid "reverse-index file %s has unknown signature"
+msgstr "файл зворотного індексу %s має невідомий підпис"
+
+#, c-format
+msgid "reverse-index file %s has unsupported version %<PRIu32>"
+msgstr "файл зворотного індексу %s має непідтримувану версію %<PRIu32>"
+
+#, c-format
+msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
+msgstr ""
+"файл зворотного індексу %s має непідтримуваний хеш-ідентифікатор %<PRIu32>"
+
+msgid "invalid checksum"
+msgstr "неприпустима контрольна сума"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr ""
+"невірна позиція зворортного індексу у %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
+msgid "cannot both write and verify reverse index"
+msgstr "неможливо одночасно записувати та звіряти зворотний індекс"
+
+#, c-format
+msgid "could not stat: %s"
+msgstr "не вдалося виконати stat: %s"
+
+#, c-format
+msgid "failed to make %s readable"
+msgstr "не вдалося зробити %s читабельним"
+
+#, c-format
+msgid "could not write '%s' promisor file"
+msgstr "не вдалося записати promisor файл \"%s\""
+
+msgid "offset before end of packfile (broken .idx?)"
+msgstr "зміщення перед кінцем файла пакунка (пошкоджений .idx?)"
+
+#, c-format
+msgid "packfile %s cannot be mapped%s"
+msgstr "файл пакунка %s не може бути mapped%s"
+
+#, c-format
+msgid "offset before start of pack index for %s (corrupt index?)"
+msgstr "зміщення перед початком індекса пакунка для %s (пошкоджений індекс?)"
+
+#, c-format
+msgid "offset beyond end of pack index for %s (truncated index?)"
+msgstr "зміщення за межою кінця індекса пакунка для %s (зрізаний індекс?)"
+
+#, c-format
+msgid "malformed expiration date '%s'"
+msgstr "невірно сформована дата закінчення терміну дії \"%s\""
+
+#, c-format
+msgid "option `%s' expects \"always\", \"auto\", or \"never\""
+msgstr "опція \"%s\" очікує \"always\", \"auto\" або \"never\""
+
+#, c-format
+msgid "malformed object name '%s'"
+msgstr "невірно сформована назва обʼєкта \"%s\""
+
+#, c-format
+msgid "option `%s' expects \"%s\" or \"%s\""
+msgstr "опція \"%s\" очікує \"%s\" або \"%s\""
+
+#, c-format
+msgid "%s requires a value"
+msgstr "%s потребує значення"
+
+#, c-format
+msgid "%s is incompatible with %s"
+msgstr "%s несумісний з %s"
+
+#, c-format
+msgid "%s : incompatible with something else"
+msgstr "%s : несумісний з чимось іншим"
+
+#, c-format
+msgid "%s takes no value"
+msgstr "%s не приймає значення"
+
+#, c-format
+msgid "%s isn't available"
+msgstr "%s недоступний"
+
+#, c-format
+msgid "%s expects a non-negative integer value with an optional k/m/g suffix"
+msgstr "%s очікує невід'ємне ціле значення з опціональним суфіксом k/m/g"
+
+#, c-format
+msgid "ambiguous option: %s (could be --%s%s or --%s%s)"
+msgstr "неоднозначна опція: %s (може бути --%s%s або --%s%s)"
+
+#, c-format
+msgid "did you mean `--%s` (with two dashes)?"
+msgstr "ви мали на увазі \"--%s\" (з двома рисками)?"
+
+#, c-format
+msgid "alias of --%s"
+msgstr "псевдонім для --%s"
+
+msgid "need a subcommand"
+msgstr "потрібна підкоманда"
+
+#, c-format
+msgid "unknown option `%s'"
+msgstr "невідома опція \"%s\""
+
+#, c-format
+msgid "unknown switch `%c'"
+msgstr "невідомий перемикач \"%c\""
+
+#, c-format
+msgid "unknown non-ascii option in string: `%s'"
+msgstr "невідомий non-ascii параметр у рядку: \"%s\""
+
+msgid "..."
+msgstr "..."
+
+#, c-format
+msgid "usage: %s"
+msgstr "використання: %s"
+
+#. TRANSLATORS: the colon here should align with the
+#. one in "usage: %s" translation.
+#.
+
+#, c-format
+msgid "   or: %s"
+msgstr "         або: %s"
+
+#. TRANSLATORS: You should only need to translate this format
+#. string if your language is a RTL language (e.g. Arabic,
+#. Hebrew etc.), not if it's a LTR language (e.g. German,
+#. Russian, Chinese etc.).
+#. *
+#. When a translated usage string has an embedded "\n" it's
+#. because options have wrapped to the next line. The line
+#. after the "\n" will then be padded to align with the
+#. command name, such as N_("git cmd [opt]\n<8
+#. spaces>[opt2]"), where the 8 spaces are the same length as
+#. "git cmd ".
+#. *
+#. This format string prints out that already-translated
+#. line. The "%*s" is whitespace padding to account for the
+#. padding at the start of the line that we add in this
+#. 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"
+
+#, c-format
+msgid "    %s"
+msgstr "    %s"
+
+msgid "-NUM"
+msgstr "-NUM"
+
+msgid "expiry-date"
+msgstr "закінчення строку дії"
+
+msgid "no-op (backward compatibility)"
+msgstr "не працює (зворотна сумісність)"
+
+msgid "be more verbose"
+msgstr "надавати більш розгорнутий вивід"
+
+msgid "be more quiet"
+msgstr "надавати менш розгорнутий вивід"
+
+msgid "use <n> digits to display object names"
+msgstr "використовувати <n> цифр для відображення назв обʼєктів"
+
+msgid "prefixed path to initial superproject"
+msgstr "префіксний шлях до початкового суперпроекту"
+
+msgid "how to strip spaces and #comments from message"
+msgstr "як прибирати пробіли та #коментарі з допису"
+
+msgid "read pathspec from file"
+msgstr "прочитати визначник шляху з файлу"
+
+msgid ""
+"with --pathspec-from-file, pathspec elements are separated with NUL character"
+msgstr ""
+"за допомогою --pathspec-from-file елементи визначника шляху відокремлюються "
+"символом NUL"
+
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr "Не вдалося зробити %s доступним для запису групою"
+
+msgid "Escape character '\\' not allowed as last character in attr value"
+msgstr ""
+"Символ екранування \"\\\" не дозволяється як останній символ у значенні "
+"атрибута"
+
+msgid "Only one 'attr:' specification is allowed."
+msgstr "Дозволений лише один визначник \"attr:\"."
+
+msgid "attr spec must not be empty"
+msgstr "визначник атрибута повинен бути не порожнім"
+
+#, c-format
+msgid "invalid attribute name %s"
+msgstr "невірна назва атрибуту %s"
+
+msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
+msgstr "глобальні параметри визначника шляху \"glob\" та \"noglob\" несумісні"
+
+msgid ""
+"global 'literal' pathspec setting is incompatible with all other global "
+"pathspec settings"
+msgstr ""
+"глобальний параметр \"literal\" визначника шляху несумісний з усіма іншими "
+"глобальними параметрами визначника шляху"
+
+msgid "invalid parameter for pathspec magic 'prefix'"
+msgstr ""
+"неприпустимий параметр для магічного значення \"prefix\" визначника шляху"
+
+#, c-format
+msgid "Invalid pathspec magic '%.*s' in '%s'"
+msgstr "Неприпустиме магічне значення \"%.*s\" для визначника шляху в \"%s\""
+
+#, c-format
+msgid "Missing ')' at the end of pathspec magic in '%s'"
+msgstr ""
+"Пропущено \")\" наприкінці магічного значення для визначника шляху в \"%s\""
+
+#, c-format
+msgid "Unimplemented pathspec magic '%c' in '%s'"
+msgstr "Нереалізоване магічне значення \"%c\" для визначника шляху в \"%s\""
+
+#, c-format
+msgid "%s: 'literal' and 'glob' are incompatible"
+msgstr "%s: \"literal\" та \"glob\" несумісні"
+
+#, c-format
+msgid "%s: '%s' is outside repository at '%s'"
+msgstr "%s: \"%s\" знаходиться за межами сховища за адресою \"%s\""
+
+#, c-format
+msgid "'%s' (mnemonic: '%c')"
+msgstr "\"%s\" (мнемонічно: \"%c\")"
+
+#, c-format
+msgid "%s: pathspec magic not supported by this command: %s"
+msgstr ""
+"%s: магічне значення для визначника шляху не підтримується цією командою: %s"
+
+#, c-format
+msgid "pathspec '%s' is beyond a symbolic link"
+msgstr "визначник шляху \"%s\" знаходиться за межами символьного посилання"
+
+#, c-format
+msgid "line is badly quoted: %s"
+msgstr "рядок взято в лапки невірно: %s"
+
+msgid "unable to write flush packet"
+msgstr "не вдалося записати flush пакет"
+
+msgid "unable to write delim packet"
+msgstr "не вдалося записати delim пакет"
+
+msgid "unable to write response end packet"
+msgstr "не вдалося записати response end пакет"
+
+msgid "flush packet write failed"
+msgstr "не вдалося записати flush пакет"
+
+msgid "protocol error: impossibly long line"
+msgstr "помилка протоколу: неймовірно довгий рядок"
+
+msgid "packet write with format failed"
+msgstr "не вдалося записати пакет з форматуванням"
+
+msgid "packet write failed - data exceeds max packet size"
+msgstr ""
+"не вдалося записати пакет - дані перевищують максимальний розмір пакета"
+
+#, c-format
+msgid "packet write failed: %s"
+msgstr "не вдалося записати пакет: %s"
+
+msgid "read error"
+msgstr "помилка зчитування"
+
+msgid "the remote end hung up unexpectedly"
+msgstr "віддалене призначення несподівано відключилося"
+
+#, c-format
+msgid "protocol error: bad line length character: %.4s"
+msgstr "помилка протоколу: невірний символ довжини рядка: %.4s"
+
+#, c-format
+msgid "protocol error: bad line length %d"
+msgstr "помилка протоколу: невірна довжина рядка %d"
+
+#, c-format
+msgid "remote error: %s"
+msgstr "помилка віддаленого призначення: %s"
+
+msgid "Refreshing index"
+msgstr "Оновлення індекса"
+
+#, c-format
+msgid "unable to create threaded lstat: %s"
+msgstr "не вдалося створити потоковий lstat: %s"
+
+msgid "unable to parse --pretty format"
+msgstr "не вдалося розібрати --pretty формат"
+
+msgid "promisor-remote: unable to fork off fetch subprocess"
+msgstr "promisor-remote: не вдалося розгалужити підпроцес отримання"
+
+msgid "promisor-remote: could not write to fetch subprocess"
+msgstr "promisor-remote: не вдалося записати до підпроцесу отримання"
+
+msgid "promisor-remote: could not close stdin to fetch subprocess"
+msgstr "promisor-remote: не вдалося закрити stdin для підпроцесу отримання"
+
+#, c-format
+msgid "promisor remote name cannot begin with '/': %s"
+msgstr "назва віддаленого promisor не може починатися з \"/\": %s"
+
+#, c-format
+msgid "could not fetch %s from promisor remote"
+msgstr "не вдалося отримати %s з віддаленого promisor"
+
+msgid "object-info: expected flush after arguments"
+msgstr "object-info: очікувався flush після аргументів"
+
+msgid "Removing duplicate objects"
+msgstr "Видалення дублікатів обʼєктів"
+
+msgid "could not start `log`"
+msgstr "не вдалося розпочати \"log\""
+
+msgid "could not read `log` output"
+msgstr "не вдалося прочитати \"log\" вивід"
+
+#, c-format
+msgid "could not parse commit '%s'"
+msgstr "не вдалося розібрати коміт \"%s\""
+
+#, c-format
+msgid ""
+"could not parse first line of `log` output: did not start with 'commit ': "
+"'%s'"
+msgstr ""
+"не вдалося розібрати перший рядок \"log\" виводу: не починався з \"commit "
+"\"': \"%s\""
+
+#, c-format
+msgid "could not parse git header '%.*s'"
+msgstr "не вдалося розібрати git заголовок \"%.*s\""
+
+msgid "failed to generate diff"
+msgstr "не вдалося згенерувати різницю"
+
+#, c-format
+msgid "could not parse log for '%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)"
+msgstr "не додаємо псевдонім файлу \"%s\" (\"%s\" вже існує в індексі)"
+
+msgid "cannot create an empty blob in the object database"
+msgstr "неможливо створити порожній blob в базі даних обʼєктів"
+
+#, c-format
+msgid "%s: can only add regular files, symbolic links or git-directories"
+msgstr ""
+"%s: може додавати лише звичайні файли, символьні посилання або git-директорії"
+
+#, c-format
+msgid "unable to index file '%s'"
+msgstr "не вдалося проіндексувати файл \"%s\""
+
+#, c-format
+msgid "unable to add '%s' to index"
+msgstr "не вдалося додати \"%s\" до індексу"
+
+#, c-format
+msgid "unable to stat '%s'"
+msgstr "не вдалося виконати stat для \"%s\""
+
+#, c-format
+msgid "'%s' appears as both a file and as a directory"
+msgstr "\"%s\" відображається як файл і як каталог"
+
+msgid "Refresh index"
+msgstr "Оновити індекс"
+
+#, c-format
+msgid ""
+"index.version set, but the value is invalid.\n"
+"Using version %i"
+msgstr ""
+"index.version встановлено, але значення неприпустиме.\n"
+"Використання версії %i"
+
+#, c-format
+msgid ""
+"GIT_INDEX_VERSION set, but the value is invalid.\n"
+"Using version %i"
+msgstr ""
+"GIT_INDEX_VERSION встановлено, але значення неприпустиме.\n"
+"Використання версії %i"
+
+#, c-format
+msgid "bad signature 0x%08x"
+msgstr "невірний підпис 0x%08x"
+
+#, c-format
+msgid "bad index version %d"
+msgstr "невірна версія індексу %d"
+
+msgid "bad index file sha1 signature"
+msgstr "невірний sha1 підпис індексного файлу"
+
+#, c-format
+msgid "index uses %.4s extension, which we do not understand"
+msgstr "індекс використовує %.4s розширення, яке ми не розуміємо"
+
+#, c-format
+msgid "ignoring %.4s extension"
+msgstr "ігнорування %.4s розширення"
+
+#, c-format
+msgid "unknown index entry format 0x%08x"
+msgstr "невідомий формат запису індексу 0x%08x"
+
+#, c-format
+msgid "malformed name field in the index, near path '%s'"
+msgstr "невірно сформоване поле назви в індексі біля шляху \"%s\""
+
+msgid "unordered stage entries in index"
+msgstr "невпорядковані записи в індексі"
+
+#, c-format
+msgid "multiple stage entries for merged file '%s'"
+msgstr "багатоступеневі записи для злитого файлу \"%s\""
+
+#, c-format
+msgid "unordered stage entries for '%s'"
+msgstr "невпорядковані записи індексу для '%s'"
+
+#, c-format
+msgid "unable to create load_cache_entries thread: %s"
+msgstr "не вдалося створити потік load_cache_entries: %s"
+
+#, c-format
+msgid "unable to join load_cache_entries thread: %s"
+msgstr "не вдалося приєднатися до потоку load_cache_entries: %s"
+
+#, c-format
+msgid "%s: index file open failed"
+msgstr "%s: не вдалося відкрити індексний файл"
+
+#, c-format
+msgid "%s: cannot stat the open index"
+msgstr "%s: не вдалося виконати stat відкритого індексу"
+
+#, c-format
+msgid "%s: index file smaller than expected"
+msgstr "%s: індексний файл менший, ніж очікувався"
+
+#, c-format
+msgid "%s: unable to map index file%s"
+msgstr "%s: не вдалося зіставити індексний файл%s"
+
+#, c-format
+msgid "unable to create load_index_extensions thread: %s"
+msgstr "не вдалося створити потік load_index_extensions: %s"
+
+#, c-format
+msgid "unable to join load_index_extensions thread: %s"
+msgstr "не вдалося приєднатися до потоку load_index_extensions: %s"
+
+#, c-format
+msgid "could not freshen shared index '%s'"
+msgstr "не вдалося оновити спільний індекс \"%s\""
+
+#, c-format
+msgid "broken index, expect %s in %s, got %s"
+msgstr "пошкоджений індекс, очікувався %s у %s, отримано %s"
+
+msgid "cannot write split index for a sparse index"
+msgstr "неможливо записати розщеплений індекс для розрідженого індексу"
+
+msgid "failed to convert to a sparse-index"
+msgstr "не вдалося перетворити в sparse-index"
+
+#, c-format
+msgid "could not stat '%s'"
+msgstr "не вдалося виконати stat '%s'"
+
+#, c-format
+msgid "unable to open git dir: %s"
+msgstr "не вдалося відкрити git-директорію: %s"
+
+#, c-format
+msgid "unable to unlink: %s"
+msgstr "не вдалося видалити: %s"
+
+#, c-format
+msgid "cannot fix permission bits on '%s'"
+msgstr "неможливо виправити біти дозволу на \"%s\""
+
+#, c-format
+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"
+"Or you can abort the rebase with 'git rebase --abort'.\n"
+msgstr ""
+"Ви можете виправити це командою \"git rebase --edit-todo\", а потім "
+"запустити \"git rebase --continue\".\n"
+"Або ви можете перервати перебазування за допомогою \"git rebase --abort\".\n"
+
+#, c-format
+msgid ""
+"unrecognized setting %s for option rebase.missingCommitsCheck. Ignoring."
+msgstr ""
+"нерозпізнане значення %s для опції rebase.missingCommitsCheck. Ігнорується."
+
+msgid ""
+"\n"
+"Commands:\n"
+"p, pick <commit> = use commit\n"
+"r, reword <commit> = use commit, but edit the commit message\n"
+"e, edit <commit> = use commit, but stop for amending\n"
+"s, squash <commit> = use commit, but meld into previous commit\n"
+"f, fixup [-C | -c] <commit> = like \"squash\" but keep only the previous\n"
+"                   commit's log message, unless -C is used, in which case\n"
+"                   keep only this commit's message; -c is same as -C but\n"
+"                   opens the editor\n"
+"x, exec <command> = run command (the rest of the line) using shell\n"
+"b, break = stop here (continue rebase later with 'git rebase --continue')\n"
+"d, drop <commit> = remove commit\n"
+"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"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
+"\n"
+"These lines can be re-ordered; they are executed from top to bottom.\n"
+msgstr ""
+"\n"
+"Команди:\n"
+"p, pick <коміт> = використати коміт\n"
+"r, reword <коміт> = використати коміт, але відредагувати допис до коміту\n"
+"e, edit <коміт> = використати коміт, але зупинитись для внесення поправок\n"
+"s, squash <коміт> = використати коміт, але обʼєднати з попереднім комітом\n"
+"f, fixup [-C | -c] <коміт> = як \"squash\", але зберігає лише попередній\n"
+"                   допис до коміту, якщо тільки не вказана опція -С, у якому "
+"разі\n"
+"                   зберігається лише допис до цього коміту; -c - те саме, що "
+"й -C, але\n"
+"                   відкриває редактор\n"
+"x, exec <команда> = виконати команду (решту рядка) за допомогою shell\n"
+"b, break = зупинитись тут (продовжити перебазування пізніше за допомогою "
+"'git rebase --continue')\n"
+"d, drop <коміт> = видалити коміт\n"
+"l, label <мітка> = помітити поточний HEAD назвою\n"
+"t, reset <мітка> = скинути HEAD до мітки\n"
+"m, merge [-C <коміт> | -c <коміт>] <мітка> [# <однорядковий допис>]\n"
+"        створити коміт злиття, використовуючи допис до початкового коміту\n"
+"        злиття (або однорядковий допис, якщо не було вказано коміт\n"
+"        злиття); використовуйте -c <коміт>, щоб перефразувати допис до "
+"коміту\n"
+"u, update-ref <посилання> = відстежити заповнювач для <посилання>, яке "
+"потрібно оновити\n"
+"                      до цієї позиції у нових комітах. <посилання>\n"
+"                      оновлюється в кінці перебазування\n"
+"\n"
+"Ці рядки можна переупорядкувати; вони виконуються зверху вниз.\n"
+
+#, c-format
+msgid "Rebase %s onto %s (%d command)"
+msgid_plural "Rebase %s onto %s (%d commands)"
+msgstr[0] "Перебазування %s на %s (%d команда)"
+msgstr[1] "Перебазування %s на %s (%d команди)"
+msgstr[2] "Перебазування %s на %s (%d команд)"
+
+msgid ""
+"\n"
+"Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
+msgstr ""
+"\n"
+"Не видаляйте жодного рядка. Використовуйте \"drop\", щоб явно видалити "
+"коміт.\n"
+
+msgid ""
+"\n"
+"If you remove a line here THAT COMMIT WILL BE LOST.\n"
+msgstr ""
+"\n"
+"Якщо ви видалите тут рядок, ЦЕЙ КОМІТ БУДЕ ВТРАЧЕНО.\n"
+
+msgid ""
+"\n"
+"You are editing the todo file of an ongoing interactive rebase.\n"
+"To continue rebase after editing, run:\n"
+"    git rebase --continue\n"
+"\n"
+msgstr ""
+"\n"
+"Ви редагуєте файл todo поточного інтерактивного перебазування.\n"
+"Щоб продовжити перебазування після редагування, виконайте:\n"
+"    git rebase --continue\n"
+
+msgid ""
+"\n"
+"However, if you remove everything, the rebase will be aborted.\n"
+"\n"
+msgstr ""
+"\n"
+"Однак, якщо ви видалите все, перебазування буде перервано.\n"
+"\n"
+
+#, c-format
+msgid "could not write '%s'."
+msgstr "не вдалося записати \"%s\"."
+
+#, c-format
+msgid ""
+"Warning: some commits may have been dropped accidentally.\n"
+"Dropped commits (newer to older):\n"
+msgstr ""
+"Попередження: деякі коміти могли бути видалені випадково.\n"
+"Скинуті коміти (від новіших до старіших):\n"
+
+#, c-format
+msgid ""
+"To avoid this message, use \"drop\" to explicitly remove a commit.\n"
+"\n"
+"Use 'git config rebase.missingCommitsCheck' to change the level of "
+"warnings.\n"
+"The possible behaviours are: ignore, warn, error.\n"
+"\n"
+msgstr ""
+"Щоб уникнути цього повідомлення, використовуйте \"drop\" для явного "
+"видалення коміту.\n"
+"\n"
+"Використовуйте \"git config rebase.missingCommitsCheck\" для зміни рівня "
+"попереджень.\n"
+"Можливі варіанти поведінки: ignore, warn, error.\n"
+
+#, c-format
+msgid "%s: 'preserve' superseded by 'merges'"
+msgstr "%s: \"preserve\" замінено на \"merges\""
+
+msgid "gone"
+msgstr "відсутнє"
+
+#, c-format
+msgid "ahead %d"
+msgstr "попереду %d"
+
+#, c-format
+msgid "behind %d"
+msgstr "позаду %d"
+
+#, c-format
+msgid "ahead %d, behind %d"
+msgstr "попереду %d, позаду %d"
+
+#, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) не приймає аргументів"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "нерозпізнаний %%(%.*s) аргумент: %s"
+
+#, c-format
+msgid "expected format: %%(color:<color>)"
+msgstr "очікуваний формат: %%(color:<колір>)"
+
+#, c-format
+msgid "unrecognized color: %%(color:%s)"
+msgstr "нерозпізнаний колір: %%(color:%s)"
+
+#, c-format
+msgid "Integer value expected refname:lstrip=%s"
+msgstr "Очікувалось ціле число refname:lstrip=%s"
+
+#, c-format
+msgid "Integer value expected refname:rstrip=%s"
+msgstr "Очікувалось ціле число refname:rstrip=%s"
+
+#, c-format
+msgid "expected %%(trailers:key=<value>)"
+msgstr "очікувалось %%(trailers:key=<значення>)"
+
+#, c-format
+msgid "unknown %%(trailers) argument: %s"
+msgstr "невідомий %%(trailers) аргумент: %s"
+
+#, c-format
+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)"
+
+#, c-format
+msgid "expected format: %%(align:<width>,<position>)"
+msgstr "очікуваний формат: %%(align:<ширина>,<позиція>)"
+
+#, c-format
+msgid "unrecognized position:%s"
+msgstr "нерозпізнана позиція:%s"
+
+#, c-format
+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 "expected format: %%(ahead-behind:<committish>)"
+msgstr "очікуваний формат: %%(ahead-behind:<комітоподібне>)"
+
+#, c-format
+msgid "malformed field name: %.*s"
+msgstr "невірно сформована назва поля: %.*s"
+
+#, c-format
+msgid "unknown field name: %.*s"
+msgstr "невідома назва поля: %.*s"
+
+#, c-format
+msgid ""
+"not a git repository, but the field '%.*s' requires access to object data"
+msgstr "не git сховище, але поле \"%.*s\" потребує доступу до даних обʼєкта"
+
+#, c-format
+msgid "format: %%(%s) atom used without a %%(%s) atom"
+msgstr "формат: частка %%(%s) використано без частки %%(%s)"
+
+#, c-format
+msgid "format: %%(then) atom used more than once"
+msgstr "формат: %%(then) частка використана більше одного разу"
+
+#, c-format
+msgid "format: %%(then) atom used after %%(else)"
+msgstr "формат: %%(then) частка використана після %%(else)"
+
+#, c-format
+msgid "format: %%(else) atom used more than once"
+msgstr "формат: %%(else) частка використана більше одного разу"
+
+#, c-format
+msgid "format: %%(end) atom used without corresponding atom"
+msgstr "формат: %%(end) частка використана без відповідної частки"
+
+#, c-format
+msgid "malformed format string %s"
+msgstr "невірно сформований рядок форматування %s"
+
+#, c-format
+msgid "this command reject atom %%(%.*s)"
+msgstr "ця команда відхиляє частку %%(%.*s)"
+
+#, c-format
+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)"
+
+#, c-format
+msgid "(no branch, rebasing detached HEAD %s)"
+msgstr "(немає гілки, перебазування відокремленого HEAD %s)"
+
+#, c-format
+msgid "(no branch, bisect started on %s)"
+msgstr "(немає гілки, бісекцію розпочато на %s)"
+
+#, c-format
+msgid "(HEAD detached at %s)"
+msgstr "(HEAD відʼєднано на %s)"
+
+#, c-format
+msgid "(HEAD detached from %s)"
+msgstr "(HEAD відʼєднано від %s)"
+
+msgid "(no branch)"
+msgstr "(немає гілки)"
+
+#, c-format
+msgid "missing object %s for %s"
+msgstr "відсутній обʼєкт %s для %s"
+
+#, c-format
+msgid "parse_object_buffer failed on %s for %s"
+msgstr "parse_object_buffer завершився невдало на %s для %s"
+
+#, c-format
+msgid "malformed object at '%s'"
+msgstr "невірно сформований обʼєкт за адресою \"%s\""
+
+#, c-format
+msgid "ignoring ref with broken name %s"
+msgstr "ігнорування посилання з пошкодженою назвою %s"
+
+#, c-format
+msgid "ignoring broken ref %s"
+msgstr "ігнорування пошкоджених посилань %s"
+
+#, c-format
+msgid "format: %%(end) atom missing"
+msgstr "формат: %%(end) частка відсутня"
+
+#, c-format
+msgid "malformed object name %s"
+msgstr "невірно сформована назва обʼєкта %s"
+
+#, c-format
+msgid "option `%s' must point to a commit"
+msgstr "опція \"%s\" повинна вказувати на коміт"
+
+msgid "key"
+msgstr "ключ"
+
+msgid "field name to sort on"
+msgstr "назва поля для сортування"
+
+msgid "exclude refs which match pattern"
+msgstr "виключити посилання, які збігаються з шаблоном"
+
+#, c-format
+msgid "not a reflog: %s"
+msgstr "не є журналом посилань: %s"
+
+#, c-format
+msgid "no reflog for '%s'"
+msgstr "немає журналу посилань для \"%s\""
+
+#, c-format
+msgid "%s does not point to a valid object!"
+msgstr "%s не вказує на допустимий обʼєкт!"
+
+#, c-format
+msgid ""
+"Using '%s' as the name for the initial branch. This default branch name\n"
+"is subject to change. To configure the initial branch name to use in all\n"
+"of your new repositories, which will suppress this warning, call:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Names commonly chosen instead of 'master' are 'main', 'trunk' and\n"
+"'development'. The just-created branch can be renamed via this command:\n"
+"\n"
+"\tgit branch -m <name>\n"
+msgstr ""
+"Використання \"%s\" як назви початкової гілки. Назву гілки за замовчуванням\n"
+"може бути змінено. Щоб налаштувати назву початкової гілки для використання у "
+"всіх\n"
+"ваших нових сховищах, що приховає це попередження, викличте\n"
+"\n"
+"\tgit config --global init.defaultBranch <назва>.\n"
+"\n"
+"Замість \"master\" зазвичай використовують такі назви, як \"main\", "
+"\"trunk\" та\n"
+"\"development\". Щойно створену гілку можна перейменувати за допомогою цієї "
+"команди:\n"
+"\n"
+"\tgit branch -m <назва>\n"
+
+#, c-format
+msgid "could not retrieve `%s`"
+msgstr "не вдалося отримати \"%s\""
+
+#, c-format
+msgid "invalid branch name: %s = %s"
+msgstr "неприпустима назва гілки: %s = %s"
+
+#, c-format
+msgid "ignoring dangling symref %s"
+msgstr "ігнорування висячих symref %s"
+
+#, c-format
+msgid "log for ref %s has gap after %s"
+msgstr "лог для посилання %s має пропуск після %s"
+
+#, c-format
+msgid "log for ref %s unexpectedly ended on %s"
+msgstr "лог для посилання %s несподівано завершився на %s"
+
+#, c-format
+msgid "log for %s is empty"
+msgstr "лог для %s порожній"
+
+#, c-format
+msgid "refusing to update ref with bad name '%s'"
+msgstr "відмовлено в оновленні посилання з невірною назвою \"%s\""
+
+#, c-format
+msgid "update_ref failed for ref '%s': %s"
+msgstr "update_ref завершився невдало для посилання \"%s\": %s"
+
+#, c-format
+msgid "multiple updates for ref '%s' not allowed"
+msgstr "багатократні оновлення для посилання \"%s\" заборонені"
+
+msgid "ref updates forbidden inside quarantine environment"
+msgstr "оновлення посилань заборонено у карантинному середовищі"
+
+msgid "ref updates aborted by hook"
+msgstr "оновлення посилань перервано гачком"
+
+#, c-format
+msgid "'%s' exists; cannot create '%s'"
+msgstr "\"%s\" існує; неможливо створити \"%s\""
+
+#, c-format
+msgid "cannot process '%s' and '%s' at the same time"
+msgstr "неможливо обробити \"%s\" і \"%s\" одночасно"
+
+#, c-format
+msgid "could not remove reference %s"
+msgstr "не вдалося видалити посилання %s"
+
+#, c-format
+msgid "could not delete reference %s: %s"
+msgstr "не вдалося видалити посилання %s: %s"
+
+#, c-format
+msgid "could not delete references: %s"
+msgstr "не вдалося видалити посилання: %s"
+
+#, c-format
+msgid "invalid refspec '%s'"
+msgstr "неприпустимий визначник посилання \"%s\""
+
+#, c-format
+msgid "invalid quoting in push-option value: '%s'"
+msgstr "неприпустимі лапки у значенні push-опції: \"%s\""
+
+#, c-format
+msgid "%sinfo/refs not valid: is this a git repository?"
+msgstr "%sinfo/refs не дійсні: це git сховище?"
+
+msgid "invalid server response; expected service, got flush packet"
+msgstr ""
+"неприпустима відповідь сервера; очікувалось service, отримано flush пакет"
+
+#, c-format
+msgid "invalid server response; got '%s'"
+msgstr "неприпустима відповідь сервера; отримано \"%s\""
+
+#, c-format
+msgid "repository '%s' not found"
+msgstr "сховище \"%s\" не знайдено"
+
+#, c-format
+msgid "Authentication failed for '%s'"
+msgstr "Невдала аутентифікація для \"%s\""
+
+#, c-format
+msgid "unable to access '%s' with http.pinnedPubkey configuration: %s"
+msgstr ""
+"не вдалося отримати доступ до \"%s\" з конфігурацією http.pinnedPubkey: %s"
+
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr "не вдалося отримати доступ до \"%s\": %s"
+
+#, c-format
+msgid "redirecting to %s"
+msgstr "перенаправлення на %s"
+
+msgid "shouldn't have EOF when not gentle on EOF"
+msgstr "не повинен мати EOF, якщо не є обережним з EOF"
+
+msgid "remote server sent unexpected response end packet"
+msgstr "віддалений сервер надіслав неочікуваний response end пакет"
+
+msgid "unable to rewind rpc post data - try increasing http.postBuffer"
+msgstr ""
+"не вдалося перемотати  вперед rpc post дані - спробуйте збільшити http."
+"postBuffer"
+
+#, c-format
+msgid "remote-curl: bad line length character: %.4s"
+msgstr "remote-curl: невірний символ довжини рядка: %.4s"
+
+msgid "remote-curl: unexpected response end packet"
+msgstr "remote-curl: неочікуваний response end пакет"
+
+#, c-format
+msgid "RPC failed; %s"
+msgstr "RPC завершився невдало; %s"
+
+msgid "cannot handle pushes this big"
+msgstr "неможливо впоратися з такими великими надсиланнями"
+
+#, c-format
+msgid "cannot deflate request; zlib deflate error %d"
+msgstr "неможливо запакувати запит; zlib помилка пакування %d"
+
+#, c-format
+msgid "cannot deflate request; zlib end error %d"
+msgstr "неможливо запакувати запит; zlib помилка завершення %d"
+
+#, c-format
+msgid "%d bytes of length header were received"
+msgstr "%d байтів заголовку було отримано"
+
+#, c-format
+msgid "%d bytes of body are still expected"
+msgstr "%d байтів тіла все ще очікуються"
+
+msgid "dumb http transport does not support shallow capabilities"
+msgstr "засіб передачі dumb http не підтримує shallow здібності"
+
+msgid "fetch failed."
+msgstr "отримання завершилось невдало."
+
+msgid "cannot fetch by sha1 over smart http"
+msgstr "неможливо отримати дані за допомогою sha1 через smart http"
+
+#, c-format
+msgid "protocol error: expected sha/ref, got '%s'"
+msgstr "помилка протоколу: очікувалось sha/ref, отримано \"%s\""
+
+#, c-format
+msgid "http transport does not support %s"
+msgstr "http засіб передачі не підтримує %s"
+
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "помилка протоколу: очікувалось \"<url> <шлях>\", пропущено пробіл"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "не вдалося завантажити файл за URL-адресою \"%s\""
+
+msgid "git-http-push failed"
+msgstr "git-http-push завершився невдало"
+
+msgid "remote-curl: usage: git remote-curl <remote> [<url>]"
+msgstr ""
+"remote-curl: використання: git remote-curl <віддаленe-призначення> [<url>]"
+
+msgid "remote-curl: error reading command stream from git"
+msgstr "remote-curl: помилка зчитування потоку команд з git"
+
+msgid "remote-curl: fetch attempted without a local repo"
+msgstr "remote-curl: спроба отримання без локального сховища"
+
+#, c-format
+msgid "remote-curl: unknown command '%s' from git"
+msgstr "remote-curl: невідома команда \"%s\" з git"
+
+#, c-format
+msgid "config remote shorthand cannot begin with '/': %s"
+msgstr "скорочення віддаленої конфігураціі не може починатися з '/': %s"
+
+msgid "more than one receivepack given, using the first"
+msgstr "надано більше одного пакунка для отримання, використано перший"
+
+msgid "more than one uploadpack given, using the first"
+msgstr "надано більше одного пакунка для завантаження, використано перший"
+
+#, c-format
+msgid "unrecognized value transfer.credentialsInUrl: '%s'"
+msgstr "нерозпізнане значення transfer.credentialsInUrl: '%s'"
+
+#, c-format
+msgid "URL '%s' uses plaintext credentials"
+msgstr "URL-адреса \"%s\" використовує облікові дані у відкритому тексті"
+
+#, c-format
+msgid "Cannot fetch both %s and %s to %s"
+msgstr "Неможливо отримати як %s, так і %s до %s"
+
+#, c-format
+msgid "%s usually tracks %s, not %s"
+msgstr "%s зазвичай відстежує %s, а не %s"
+
+#, c-format
+msgid "%s tracks both %s and %s"
+msgstr "%s відстежує як %s, так і %s"
+
+#, c-format
+msgid "key '%s' of pattern had no '*'"
+msgstr "ключ '%s' шаблону не містив '*'"
+
+#, c-format
+msgid "value '%s' of pattern has no '*'"
+msgstr "значення '%s' шаблону не містить '*'"
+
+#, c-format
+msgid "src refspec %s does not match any"
+msgstr "визначник посилання джерела %s не збігається з жодним"
+
+#, c-format
+msgid "src refspec %s matches more than one"
+msgstr "визначник посилання джерела %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"
+"starting with \"refs/\"). We tried to guess what you meant by:\n"
+"\n"
+"- Looking for a ref that matches '%s' on the remote side.\n"
+"- Checking if the <src> being pushed ('%s')\n"
+"  is a ref in \"refs/{heads,tags}/\". If so we add a corresponding\n"
+"  refs/{heads,tags}/ prefix on the remote side.\n"
+"\n"
+"Neither worked, so we gave up. You must fully qualify the ref."
+msgstr ""
+"Призначення, що ви вказали, не є повною назвою посилання (такою,\n"
+"що починається з \"refs/\"). Ми спробували вгадати, що ви мали на увазі "
+"через:\n"
+"\n"
+"- Пошук посилання, яке відповідає \"%s\" на віддаленій стороні.\n"
+"- Перевірку, чи є <джерело> надсилання, (\"%s\")\n"
+"  посиланням у \"refs/{heads,tags}/\". Якщо так, то ми додаємо відповідний\n"
+"  refs/{heads,tags}/ префікс на віддаленій стороні.\n"
+"\n"
+"Ні те, ні інше не спрацювало, тому ми здалися. Ви повинні повністю "
+"кваліфікувати посилання."
+
+#, c-format
+msgid ""
+"The <src> part of the refspec is a commit object.\n"
+"Did you mean to create a new branch by pushing to\n"
+"'%s:refs/heads/%s'?"
+msgstr ""
+"Частина <джерело> визаначника посилання є об’єктом коміту.\n"
+"Ви хотіли створити нову гілку, надіславши зміни до\n"
+"\"%s:refs/heads/%s\"?"
+
+#, c-format
+msgid ""
+"The <src> part of the refspec is a tag object.\n"
+"Did you mean to create a new tag by pushing to\n"
+"'%s:refs/tags/%s'?"
+msgstr ""
+"Частина <джерело> визаначника посилання є об’єктом тегу.\n"
+"Ви хотіли створити новий тег, надіславши зміни до\n"
+"\"%s:refs/tags/%s\"?"
+
+#, c-format
+msgid ""
+"The <src> part of the refspec is a tree object.\n"
+"Did you mean to tag a new tree by pushing to\n"
+"'%s:refs/tags/%s'?"
+msgstr ""
+"Частина <джерело> визаначника посилання є об’єктом дерева.\n"
+"Ви хотіли позначити нове дерево, надіславши зміни до\n"
+"\"%s:refs/tags/%s\"?"
+
+#, c-format
+msgid ""
+"The <src> part of the refspec is a blob object.\n"
+"Did you mean to tag a new blob by pushing to\n"
+"'%s:refs/tags/%s'?"
+msgstr ""
+"Частина <джерело> визаначника посилання є об’єктом blob.\n"
+"Ви хотіли позначити новий blob, надіславши зміни до\n"
+"\"%s:refs/tags/%s\"?"
+
+#, c-format
+msgid "%s cannot be resolved to branch"
+msgstr "%s неможливо розвʼязати в гілку"
+
+#, c-format
+msgid "unable to delete '%s': remote ref does not exist"
+msgstr "не вдалося видалити \"%s\": віддалене посилання не існує"
+
+#, c-format
+msgid "dst refspec %s matches more than one"
+msgstr "визаначник посилання призначення %s збігається з більш ніж одним"
+
+#, c-format
+msgid "dst ref %s receives from more than one src"
+msgstr "посилання призначення %s отримує з більш ніж одного src"
+
+msgid "HEAD does not point to a branch"
+msgstr "HEAD не вказує на гілку"
+
+#, c-format
+msgid "no such branch: '%s'"
+msgstr "немає такої гілки: '%s'"
+
+#, c-format
+msgid "no upstream configured for branch '%s'"
+msgstr "першоджерельне сховище не налаштовано для гілки '%s'"
+
+#, c-format
+msgid "upstream branch '%s' not stored as a remote-tracking branch"
+msgstr "висхідна гілка \"%s\" не збережена як віддалено відстежувана гілка"
+
+#, c-format
+msgid "push destination '%s' on remote '%s' has no local tracking branch"
+msgstr ""
+"шлях призначення надсилання \"%s\" на віддаленому \"%s\" не має гілки "
+"локального відстежування"
+
+#, c-format
+msgid "branch '%s' has no remote for pushing"
+msgstr "гілка \"%s\" не має віддаленого призначення для надсилання"
+
+#, c-format
+msgid "push refspecs for '%s' do not include '%s'"
+msgstr "надіслані визначники посилань для \"%s\" не включають \"%s\""
+
+msgid "push has no destination (push.default is 'nothing')"
+msgstr "надсилання не має призначення (push.default дорівнює 'nothing')"
+
+msgid "cannot resolve 'simple' push to a single destination"
+msgstr ""
+"неможливо розвʼязати \"simple\" надсилання до єдиного пункту призначення"
+
+#, c-format
+msgid "couldn't find remote ref %s"
+msgstr "не вдалося знайти віддалене посилання %s"
+
+#, c-format
+msgid "* Ignoring funny ref '%s' locally"
+msgstr "* Ігнорування кумедних посилань \"%s\" локально"
+
+#, c-format
+msgid "Your branch is based on '%s', but the upstream is gone.\n"
+msgstr "Ваша гілка базується на \"%s\", але першоджерельне сховище зникло.\n"
+
+msgid "  (use \"git branch --unset-upstream\" to fixup)\n"
+msgstr ""
+"  (використовуйте команду \"git branch --unset-upstream\", щоб виправити)\n"
+
+#, c-format
+msgid "Your branch is up to date with '%s'.\n"
+msgstr "Ваша гілка не відрізняється від \"%s\".\n"
+
+#, c-format
+msgid "Your branch and '%s' refer to different commits.\n"
+msgstr "Ваша гілка та гілка \"%s\" посилаються до різних комітів.\n"
+
+#, c-format
+msgid "  (use \"%s\" for details)\n"
+msgstr "  (використовуйте \"%s\" для отримання детальної інформації)\n"
+
+#, 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"
+
+msgid "  (use \"git push\" to publish your local commits)\n"
+msgstr "  (скористайтесь \"git push\", щоб надіслати локальні коміти)\n"
+
+#, c-format
+msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
+msgid_plural ""
+"Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
+msgstr[0] ""
+"Ваша гілка відстає від \"%s\" на %d коміт, і її можна перемотати вперед.\n"
+msgstr[1] ""
+"Ваша гілка відстає від \"%s\" на %d коміти, і її можна перемотати вперед.\n"
+msgstr[2] ""
+"Ваша гілка відстає від гілки '%s' на %d комітів, і її можна перемотати "
+"вперед.\n"
+
+msgid "  (use \"git pull\" to update your local branch)\n"
+msgstr "  (використовуйте \"git pull\", щоб оновити вашу локальну гілку)\n"
+
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit each, respectively.\n"
+msgid_plural ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commits each, respectively.\n"
+msgstr[0] ""
+"Ваша гілка і гілка '%s' розійшлися,\n"
+"і мають %d і %d різний коміт відповідно.\n"
+msgstr[1] ""
+"Ваша гілка і гілка \"%s\" розійшлися,\n"
+"і мають %d і %d різних коміти відповідно.\n"
+msgstr[2] ""
+"Ваша гілка і гілка \"%s\" розійшлися,\n"
+"і мають %d і %d різних комітів відповідно.\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'"
+msgstr "неможливо розібрати очікувану назву обʼєкту \"%s\""
+
+#, c-format
+msgid "cannot strip one component off url '%s'"
+msgstr "неможливо вилучити один компонент з url '%s'"
+
+#, c-format
+msgid "bad replace ref name: %s"
+msgstr "неприпустима назва заміни посилання: %s"
+
+#, c-format
+msgid "duplicate replace ref: %s"
+msgstr "дубльована заміна посилання: %s"
+
+#, c-format
+msgid "replace depth too high for object %s"
+msgstr "глибина заміни занадто висока для обʼєкта %s"
+
+msgid "corrupt MERGE_RR"
+msgstr "пошкоджений MERGE_RR"
+
+msgid "unable to write rerere record"
+msgstr "неможливо зробити rerere запис"
+
+#, c-format
+msgid "there were errors while writing '%s' (%s)"
+msgstr "виникли помилки під час запису \"%s\" (%s)"
+
+#, c-format
+msgid "could not parse conflict hunks in '%s'"
+msgstr "не вдалося розібрати конфліктні шматки в \"%s\""
+
+#, c-format
+msgid "failed utime() on '%s'"
+msgstr "невдалий utime() на \"%s\""
+
+#, c-format
+msgid "writing '%s' failed"
+msgstr "запис \"%s\" завершився невдало"
+
+#, c-format
+msgid "Staged '%s' using previous resolution."
+msgstr "Індексовано \"%s\" з використанням попереднього вирішення."
+
+#, c-format
+msgid "Recorded resolution for '%s'."
+msgstr "Записано вирішення для \"%s\"."
+
+#, c-format
+msgid "Resolved '%s' using previous resolution."
+msgstr "Вирішено \"%s\" з використанням попереднього вирішення."
+
+#, c-format
+msgid "cannot unlink stray '%s'"
+msgstr "неможливо видалити блукаючий \"%s\""
+
+#, c-format
+msgid "Recorded preimage for '%s'"
+msgstr "Записано попереднє зображення для \"%s\""
+
+#, c-format
+msgid "failed to update conflicted state in '%s'"
+msgstr "не вдалося оновити конфліктний стан у \"%s\""
+
+#, c-format
+msgid "no remembered resolution for '%s'"
+msgstr "немає записаного вирішення для \"%s\""
+
+#, c-format
+msgid "Updated preimage for '%s'"
+msgstr "Оновлено попереднє зображення для \"%s\""
+
+#, c-format
+msgid "Forgot resolution for '%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"
+msgstr "не вдалося визначити ревізію HEAD"
+
+#, c-format
+msgid "failed to find tree of %s"
+msgstr "не вдалося знайти дерево %s"
+
+#, c-format
+msgid "unsupported section for hidden refs: %s"
+msgstr "непідтримувана секція для прихованих посилань: %s"
+
+msgid "--exclude-hidden= passed more than once"
+msgstr "--exclude-hidden= передано більше одного разу"
+
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo записує \"%s\", який відсутній"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+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 "ваша поточна гілка виглядає пошкодженою"
+
+#, c-format
+msgid "your current branch '%s' does not have any commits yet"
+msgstr "ваша поточна гілка \"%s\" ще не має жодних комітів"
+
+msgid "object filtering requires --objects"
+msgstr "для фільтрації обʼєктів потрібен параметр --objects"
+
+msgid "-L does not yet support diff formats besides -p and -s"
+msgstr "-L поки що не підтримує diff формати, окрім -p та -s"
+
+#, c-format
+msgid "cannot create async thread: %s"
+msgstr "неможливо створити асинхронний потік: %s"
+
+#, c-format
+msgid "'%s' does not exist"
+msgstr "\"%s\" не існує"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "не вдалося переключитися на \"%s\""
+
+msgid "need a working directory"
+msgstr "потрібна робоча директорія"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Коренева директорія проекту потребує робоче дерево"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "не вдалося налаштувати %s=%s"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "не вдалося налаштувати log.excludeDecoration"
+
+msgid "could not add enlistment"
+msgstr "не вдалося додати кореневу директорію проекту"
+
+msgid "could not set recommended config"
+msgstr "не вдалося встановити рекомендовану конфігурацію"
+
+msgid "could not turn on maintenance"
+msgstr "не вдалося ввімкнути технічне обслуговування"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "не вдалося запустити FSMonitor демон"
+
+msgid "could not turn off maintenance"
+msgstr "не вдалося вимкнути технічне обслуговування"
+
+msgid "could not remove enlistment"
+msgstr "не вдалося видалити директорію верхнього рівня"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "віддалений HEAD не є гілкою: \"%.*s\""
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"не вдалося отримати назву гілки за замовчуванням з віддаленого сховища; "
+"використано локальне значення за замовчуванням"
+
+msgid "failed to get default branch name"
+msgstr "не вдалося отримати назву гілки за замовчуванням"
+
+msgid "failed to unregister repository"
+msgstr "не вдалося скасувати реєстрацію сховища"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "не вдалося зупинити FSMonitor демон"
+
+msgid "failed to delete enlistment directory"
+msgstr "не вдалося видалити кореневу директорію проекту"
+
+msgid "branch to checkout after clone"
+msgstr "гілка, на яку перейти після клонування"
+
+msgid "when cloning, create full working directory"
+msgstr "при клонуванні створювати повну робочу директорію"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr ""
+"завантажити метадані тільки для гілки, на яку буде здійснюватися перехід"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "скалярний клон [<опції>] [--] <сховище> [<директорія>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "неможливо вивести назву робочого дерева з \"%s\""
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "директорія \"%s\" вже існує"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "не вдалося отримати гілку за замовчуванням для \"%s\""
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "не вдалося налаштувати віддалене сховище в \"%s\""
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "не вдалося налаштувати \"%s\""
+
+msgid "partial clone failed; attempting full clone"
+msgstr "не вдалося зробити розріджений клон; спроба зробити повний клон"
+
+msgid "could not configure for full clone"
+msgstr "не вдалося налаштувати для повного клона"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<коренева-директорія-проекту>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "\"scalar list\" не приймає аргументів"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<коренева-директорія-проекту>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "переналаштувати всі зареєстровані кореневі директорії проекту"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <коренева-директорія-проекту>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all або <коренева-директорія-проекту>, але не обидва"
+
+#, c-format
+msgid "could not remove stale scalar.repo '%s'"
+msgstr "неможливо видалити застаріле scalar.repo \"%s\""
+
+#, c-format
+msgid "removing stale scalar.repo '%s'"
+msgstr "видалення застарілого scalar.repo \"%s\""
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "git сховище зникло у \"%s\""
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <завдання> [<коренева-директорія-проекту>]\n"
+"Завдання:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "немає такого завдання: \"%s\""
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<коренева-директорія-проекту>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <коренева-директорія-проекту>"
+
+msgid "refusing to delete current working directory"
+msgstr "відмовлено у видаленні поточної робочої директорії"
+
+msgid "include Git version"
+msgstr "включити версію Git"
+
+msgid "include Git's build options"
+msgstr "включити опції збірки Git"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C потребує наявності <директорії>"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "не вдалося змінити на \"%s\""
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c потребує <ключ>=<значення> аргумент"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <директорія>] [-c <ключ>=<значення>] <команда> [<опції>]\n"
+"\n"
+"Команди:\n"
+
+msgid "unexpected flush packet while reading remote unpack status"
+msgstr ""
+"несподіваний flush пакет під час зчитування статусу віддаленого розпакування"
+
+#, c-format
+msgid "unable to parse remote unpack status: %s"
+msgstr "не вдалося розібрати стан розпакування віддаленого сховища: %s"
+
+#, c-format
+msgid "remote unpack failed: %s"
+msgstr "віддалене розпакування не вдалося: %s"
+
+msgid "failed to sign the push certificate"
+msgstr "не вдалося підписати сертифікат надсилання"
+
+msgid "send-pack: unable to fork off fetch subprocess"
+msgstr "send-pack: не вдалося розгалужити підпроцес отримання"
+
+msgid "push negotiation failed; proceeding anyway with push"
+msgstr "перемовини з надсилання не вдалися; все одно продовжуємо надсилання"
+
+msgid "the receiving end does not support this repository's hash algorithm"
+msgstr "отримуюча сторона не підтримує хеш-алгоритм цього сховища"
+
+msgid "the receiving end does not support --signed push"
+msgstr "отримуюча сторона не підтримує --signed push"
+
+msgid ""
+"not sending a push certificate since the receiving end does not support --"
+"signed push"
+msgstr ""
+"сертифікат надсилання не відправлено, оскільки отримуюча сторона не "
+"підтримує --signed push"
+
+msgid "the receiving end does not support --atomic push"
+msgstr "отримуюча сторона не підтримує --atomic push"
+
+msgid "the receiving end does not support push options"
+msgstr "отримуюча сторона не підтримує опції push"
+
+#, c-format
+msgid "invalid commit message cleanup mode '%s'"
+msgstr "неприпустимий режим очищення дописів до коміту \"%s\""
+
+#, c-format
+msgid "could not delete '%s'"
+msgstr "не вдалося видалити \"%s\""
+
+msgid "revert"
+msgstr "вивертання"
+
+msgid "cherry-pick"
+msgstr "висмикування"
+
+msgid "rebase"
+msgstr "перебазування"
+
+#, c-format
+msgid "unknown action: %d"
+msgstr "невідома дія: %d"
+
+msgid ""
+"after resolving the conflicts, mark the corrected paths\n"
+"with 'git add <paths>' or 'git rm <paths>'"
+msgstr ""
+"після вирішення конфліктів позначте виправлені шляхи\n"
+"за допомогою \"git add <шляхи>\" або \"git rm <шляхи>\""
+
+msgid ""
+"After resolving the conflicts, mark them with\n"
+"\"git add/rm <pathspec>\", then run\n"
+"\"git cherry-pick --continue\".\n"
+"You can instead skip this commit with \"git cherry-pick --skip\".\n"
+"To abort and get back to the state before \"git cherry-pick\",\n"
+"run \"git cherry-pick --abort\"."
+msgstr ""
+"Після вирішення конфліктів позначте їх за допомогою\n"
+"\"git add/rm <визначник шляху>\", а потім виконайте\n"
+"\"git cherry-pick --continue\".\n"
+"Замість цього ви можете пропустити цей коміт за допомогою \"git cherry-pick "
+"--skip\".\n"
+"Щоб перервати процес і повернутися до стану перед \"git cherry-pick\",\n"
+"виконайте \"git cherry-pick --abort\"."
+
+msgid ""
+"After resolving the conflicts, mark them with\n"
+"\"git add/rm <pathspec>\", then run\n"
+"\"git revert --continue\".\n"
+"You can instead skip this commit with \"git revert --skip\".\n"
+"To abort and get back to the state before \"git revert\",\n"
+"run \"git revert --abort\"."
+msgstr ""
+"Після вирішення конфліктів позначте їх за допомогою\n"
+"\"git add/rm <визначник шляху>\", а потім виконайте\n"
+"\"git revert --continue\".\n"
+"Замість цього ви можете пропустити цей коміт за допомогою \"git revert --"
+"skip\".\n"
+"Щоб перервати і повернутися до стану перед \"git revert\",\n"
+"виконайте \"git revert --abort\"."
+
+#, c-format
+msgid "could not lock '%s'"
+msgstr "не вдалося зафіксувати \"%s\""
+
+#, c-format
+msgid "could not write eol to '%s'"
+msgstr "не вдалося записати eol в \"%s\""
+
+#, c-format
+msgid "failed to finalize '%s'"
+msgstr "не вдалося завершити \"%s\""
+
+#, c-format
+msgid "your local changes would be overwritten by %s."
+msgstr "ваші локальні зміни будуть перезаписані %s."
+
+msgid "commit your changes or stash them to proceed."
+msgstr "зробіть коміт або додайте ваші зміни до схову, щоб продовжити."
+
+#. TRANSLATORS: %s will be "revert", "cherry-pick" or
+#. "rebase".
+#.
+
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr "%s: Не вдалося записати новий індексний файл"
+
+msgid "unable to update cache tree"
+msgstr "не вдалося оновити дерево кешу"
+
+msgid "could not resolve HEAD commit"
+msgstr "не вдалося розпізнати HEAD коміт"
+
+#, c-format
+msgid "no key present in '%.*s'"
+msgstr "немає ключа у \"%.*s\""
+
+#, c-format
+msgid "unable to dequote value of '%s'"
+msgstr "не вдалося вилучити лапки зі значення \"%s\""
+
+msgid "'GIT_AUTHOR_NAME' already given"
+msgstr "\"GIT_AUTHOR_NAME\" вже надано"
+
+msgid "'GIT_AUTHOR_EMAIL' already given"
+msgstr "\"GIT_AUTHOR_EMAIL\" вже надано"
+
+msgid "'GIT_AUTHOR_DATE' already given"
+msgstr "\"GIT_AUTHOR_DATE\" вже надано"
+
+#, c-format
+msgid "unknown variable '%s'"
+msgstr "невідома змінна \"%s\""
+
+msgid "missing 'GIT_AUTHOR_NAME'"
+msgstr "бракує \"GIT_AUTHOR_NAME\""
+
+msgid "missing 'GIT_AUTHOR_EMAIL'"
+msgstr "бракує \"GIT_AUTHOR_EMAIL\""
+
+msgid "missing 'GIT_AUTHOR_DATE'"
+msgstr "бракує \"GIT_AUTHOR_DATE\""
+
+#, c-format
+msgid ""
+"you have staged changes in your working tree\n"
+"If these changes are meant to be squashed into the previous commit, run:\n"
+"\n"
+"  git commit --amend %s\n"
+"\n"
+"If they are meant to go into a new commit, run:\n"
+"\n"
+"  git commit %s\n"
+"\n"
+"In both cases, once you're done, continue with:\n"
+"\n"
+"  git rebase --continue\n"
+msgstr ""
+"ви маєте індексовані зміни у вашому робочому дереві\n"
+"Якщо ці зміни мають бути стиснуті у попередній коміт, запустіть:\n"
+"\n"
+"  git commit --amend %s\n"
+"\n"
+"Якщо вони мають потрапити до нового коміту, виконайте:\n"
+"\n"
+"  git commit %s\n"
+"\n"
+"В обох випадках, як тільки ви закінчите, продовжуйте за допомогою:\n"
+"\n"
+"  git rebase --continue\n"
+
+msgid "'prepare-commit-msg' hook failed"
+msgstr "\"prepare-commit-msg\" гачок завершився невдало"
+
+msgid ""
+"Your name and email address were configured automatically based\n"
+"on your username and hostname. Please check that they are accurate.\n"
+"You can suppress this message by setting them explicitly. Run the\n"
+"following command and follow the instructions in your editor to edit\n"
+"your configuration file:\n"
+"\n"
+"    git config --global --edit\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+"    git commit --amend --reset-author\n"
+msgstr ""
+"Ваше імʼя та адреса електронної пошти були налаштовані автоматично на "
+"основі\n"
+"вашого імені користувача та назви хосту. Будь ласка, перевірте їх "
+"правильність.\n"
+"Ви можете приховати це повідомлення, встановивши їх явно. Запустіть\n"
+"наступну команду і дотримуйтесь інструкцій у вашому редакторі, щоб "
+"відредагувати\n"
+"ваш конфігураційний файл:\n"
+"\n"
+"    git config --global --edit\n"
+"\n"
+"Після цього ви можете виправити особистість автора, використану для цього "
+"коміту, за допомогою\n"
+"\n"
+"    git commit --amend --reset-author\n"
+
+msgid ""
+"Your name and email address were configured automatically based\n"
+"on your username and hostname. Please check that they are accurate.\n"
+"You can suppress this message by setting them explicitly:\n"
+"\n"
+"    git config --global user.name \"Your Name\"\n"
+"    git config --global user.email you@example.com\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+"    git commit --amend --reset-author\n"
+msgstr ""
+"Ваше імʼя та адреса електронної пошти були налаштовані автоматично на "
+"основі\n"
+"вашого імені користувача та назви хосту. Будь ласка, перевірте їх "
+"правильність.\n"
+"Ви можете приховати це повідомлення, вказавши їх явно:\n"
+"\n"
+"    git config --global user.name \"Ваше Імʼя\"\n"
+"    git config --global user.email you@example.com\n"
+"\n"
+"Після цього ви можете виправити особистість автора, використану для цього "
+"коміту, за допомогою\n"
+"\n"
+"    git commit --amend --reset-author\n"
+
+msgid "couldn't look up newly created commit"
+msgstr "не вдалося знайти новостворений коміт"
+
+msgid "could not parse newly created commit"
+msgstr "не вдалося розібрати новостворений коміт"
+
+msgid "unable to resolve HEAD after creating commit"
+msgstr "не вдалося розвʼязати HEAD після створення коміту"
+
+msgid "detached HEAD"
+msgstr "відʼєднаний HEAD"
+
+msgid " (root-commit)"
+msgstr " (кореневий коміт)"
+
+msgid "could not parse HEAD"
+msgstr "неможливо розібрати HEAD"
+
+#, c-format
+msgid "HEAD %s is not a commit!"
+msgstr "HEAD %s не є комітом!"
+
+msgid "unable to parse commit author"
+msgstr "не вдалося розібрати автора коміту"
+
+#, c-format
+msgid "unable to read commit message from '%s'"
+msgstr "не вдалося прочитати допис до коміту від \"%s\""
+
+#, c-format
+msgid "invalid author identity '%s'"
+msgstr "неприпустима особистість автора \"%s\""
+
+msgid "corrupt author: missing date information"
+msgstr "пошкоджені дані про автора: відсутня інформація про дату"
+
+#, c-format
+msgid "could not update %s"
+msgstr "не вдалося оновити %s"
+
+#, c-format
+msgid "could not parse commit %s"
+msgstr "не вдалося розібрати коміт %s"
+
+#, c-format
+msgid "could not parse parent commit %s"
+msgstr "не вдалося розібрати джерельний коміт %s"
+
+#, c-format
+msgid "unknown command: %d"
+msgstr "невідома команда: %d"
+
+msgid "This is the 1st commit message:"
+msgstr "Це перший допис до коміту:"
+
+#, c-format
+msgid "This is the commit message #%d:"
+msgstr "Це допис до коміту #%d:"
+
+msgid "The 1st commit message will be skipped:"
+msgstr "Перший допис до коміту буде пропущено:"
+
+#, c-format
+msgid "The commit message #%d will be skipped:"
+msgstr "Допис до коміту #%d буде пропущено:"
+
+#, c-format
+msgid "This is a combination of %d commits."
+msgstr "Це комбінація %d комітів."
+
+#, c-format
+msgid "cannot write '%s'"
+msgstr "неможливо записати \"%s\""
+
+msgid "need a HEAD to fixup"
+msgstr "потрібен HEAD, щоб виправити"
+
+msgid "could not read HEAD"
+msgstr "не вдалося прочитати HEAD"
+
+msgid "could not read HEAD's commit message"
+msgstr "не вдалося прочитати допис до коміту HEAD"
+
+#, c-format
+msgid "could not read commit message of %s"
+msgstr "не вдалося прочитати допис до коміту %s"
+
+msgid "your index file is unmerged."
+msgstr "ваш індексний файл не злитий."
+
+msgid "cannot fixup root commit"
+msgstr "не вдалося виправити кореневий коміт"
+
+#, c-format
+msgid "commit %s is a merge but no -m option was given."
+msgstr "коміт %s - це злиття, але опція -m не була вказана."
+
+#, c-format
+msgid "commit %s does not have parent %d"
+msgstr "коміт %s не має джерела %d"
+
+#, c-format
+msgid "cannot get commit message for %s"
+msgstr "неможливо отримати допис до коміту для %s"
+
+#. TRANSLATORS: The first %s will be a "todo" command like
+#. "revert" or "pick", the second %s a SHA1.
+
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr "%s: не вдалося розібрати джерельний коміт %s"
+
+#, c-format
+msgid "could not rename '%s' to '%s'"
+msgstr "не вдалося перейменувати \"%s\" на \"%s\""
+
+#, c-format
+msgid "could not revert %s... %s"
+msgstr "не вдалося зробити вивертання %s... %s"
+
+#, c-format
+msgid "could not apply %s... %s"
+msgstr "не вдалося застосувати %s... %s"
+
+#, c-format
+msgid "dropping %s %s -- patch contents already upstream\n"
+msgstr ""
+"скидання %s %s -- вміст латки вже знаходиться у першоджерельному сховищі\n"
+
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr "git %s: не вдалося прочитати індекс"
+
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr "git %s: не вдалося оновити індекс"
+
+#, c-format
+msgid "'%s' is not a valid label"
+msgstr "\"%s\" не є припустимою міткою"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "\"%s\" не є припустимою назвою посилання"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr "update-ref потребує повної назви посилання, наприклад, refs/heads/%s"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "неприпустима команда \"%.*s\""
+
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s не приймає аргументи: \"%s\""
+
+#, c-format
+msgid "missing arguments for %s"
+msgstr "відсутні аргументи для %s"
+
+#, c-format
+msgid "could not parse '%s'"
+msgstr "не вдалося розібрати \"%s\""
+
+#, c-format
+msgid "invalid line %d: %.*s"
+msgstr "невірний рядок %d: %.*s"
+
+#, c-format
+msgid "cannot '%s' without a previous commit"
+msgstr "неможливо зробити \"%s\" без попереднього коміту"
+
+msgid "cancelling a cherry picking in progress"
+msgstr "наразі йде скасування висмикування"
+
+msgid "cancelling a revert in progress"
+msgstr "наразі йде скасування вивертання"
+
+msgid "please fix this using 'git rebase --edit-todo'."
+msgstr "будь ласка, виправте це за допомогою \"git rebase --edit-todo\"."
+
+#, c-format
+msgid "unusable instruction sheet: '%s'"
+msgstr "непридатна інструкція: \"%s\""
+
+msgid "no commits parsed."
+msgstr "не розібрано жодного коміту."
+
+msgid "cannot cherry-pick during a revert."
+msgstr "неможливо зробити висмикування під час вивертання."
+
+msgid "cannot revert during a cherry-pick."
+msgstr "неможливо зробити вивертання під час висмикування."
+
+msgid "unusable squash-onto"
+msgstr "непридатний squash-onto"
+
+#, c-format
+msgid "malformed options sheet: '%s'"
+msgstr "невірно сформований список опцій: \"%s\""
+
+msgid "empty commit set passed"
+msgstr "передано порожній набір комітів"
+
+msgid "revert is already in progress"
+msgstr "наразі вже триває вивертання"
+
+#, c-format
+msgid "try \"git revert (--continue | %s--abort | --quit)\""
+msgstr "спробуйте \"git revert (--continue | %s--abort | --quit)\""
+
+msgid "cherry-pick is already in progress"
+msgstr "наразі вже триває висмикування"
+
+#, c-format
+msgid "try \"git cherry-pick (--continue | %s--abort | --quit)\""
+msgstr "спробуйте \"git cherry-pick (--continue | %s--abort | --quit)\""
+
+#, c-format
+msgid "could not create sequencer directory '%s'"
+msgstr "не вдалося створити директорію секвенсора \"%s\""
+
+msgid "no cherry-pick or revert in progress"
+msgstr "наразі не триває ні скасування, ні висмикування"
+
+msgid "cannot resolve HEAD"
+msgstr "неможливо розпізнати HEAD"
+
+msgid "cannot abort from a branch yet to be born"
+msgstr "неможливо перервати з гілки, яка ще не народилася"
+
+#, c-format
+msgid "cannot read '%s': %s"
+msgstr "неможливо прочитати \"%s\": %s"
+
+msgid "unexpected end of file"
+msgstr "несподіваний кінець файлу"
+
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr "збережений pre-cherry-pick HEAD файл \"%s\" пошкоджено"
+
+msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
+msgstr ""
+"Здається, ви перемістили HEAD. Перемотування назад не виконується, перевірте "
+"свій HEAD!"
+
+msgid "no revert in progress"
+msgstr "наразі не виконується вивертання"
+
+msgid "no cherry-pick in progress"
+msgstr "наразі не виконується висмикування"
+
+msgid "failed to skip the commit"
+msgstr "не вдалося пропустити коміт"
+
+msgid "there is nothing to skip"
+msgstr "немає чого пропускати"
+
+#, c-format
+msgid ""
+"have you committed already?\n"
+"try \"git %s --continue\""
+msgstr ""
+"ви вже зробили коміт?\n"
+"спробуйте \"git %s --continue\""
+
+msgid "cannot read HEAD"
+msgstr "неможливо прочитати HEAD"
+
+#, c-format
+msgid "unable to copy '%s' to '%s'"
+msgstr "не вдалося скопіювати \"%s\" в \"%s\""
+
+#, c-format
+msgid ""
+"You can amend the commit now, with\n"
+"\n"
+"  git commit --amend %s\n"
+"\n"
+"Once you are satisfied with your changes, run\n"
+"\n"
+"  git rebase --continue\n"
+msgstr ""
+"Ви можете внести зміни до коміту зараз за допомогою\n"
+"\n"
+"  git commit --amend %s\n"
+"\n"
+"Після того, як ви будете задоволені своїми змінами, виконайте\n"
+"\n"
+"  git rebase --continue\n"
+
+#, c-format
+msgid "Could not apply %s... %.*s"
+msgstr "Не вдалося застосувати %s... %.*s"
+
+#, c-format
+msgid "Could not merge %.*s"
+msgstr "Не вдалося злити %.*s"
+
+#, c-format
+msgid "Executing: %s\n"
+msgstr "Виконання: %s\n"
+
+#, c-format
+msgid ""
+"execution failed: %s\n"
+"%sYou can fix the problem, and then run\n"
+"\n"
+"  git rebase --continue\n"
+"\n"
+msgstr ""
+"не вдалося виконати : %s\n"
+"%sВи можете виправити проблему, а потім виконати\n"
+"\n"
+"  git rebase --continue\n"
+
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "та внесли зміни до індексу та/або робочого дерева\n"
+
+#, c-format
+msgid ""
+"execution succeeded: %s\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"
+
+#, c-format
+msgid "illegal label name: '%.*s'"
+msgstr "неприпустима назва мітки: \"%.*s\""
+
+#, c-format
+msgid "could not resolve '%s'"
+msgstr "не вдалося розпізнати \"%s\""
+
+msgid "writing fake root commit"
+msgstr "написання підробленого кореневого коміту"
+
+msgid "writing squash-onto"
+msgstr "запис squash-onto"
+
+msgid "cannot merge without a current revision"
+msgstr "неможливо злити без поточної ревізії"
+
+#, c-format
+msgid "unable to parse '%.*s'"
+msgstr "не вдалося розібрати \"%.*s\""
+
+#, c-format
+msgid "nothing to merge: '%.*s'"
+msgstr "нічого зливати: \"%.*s\""
+
+msgid "octopus merge cannot be executed on top of a [new root]"
+msgstr "octopus злиття неможливо виконати поверх [new root]"
+
+#, c-format
+msgid "could not get commit message of '%s'"
+msgstr "не вдалося отримати допис до коміту \"%s\""
+
+#, c-format
+msgid "could not even attempt to merge '%.*s'"
+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 "здається, запущено інший процес \"rebase\"; \"%s.lock\" вже існує"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Оновлені наступні посилання з %s:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Не вдалося оновити наступні посилання з %s:\n"
+"%s"
+
+msgid "Cannot autostash"
+msgstr "Неможливо зробити автосхов"
+
+#, c-format
+msgid "Unexpected stash response: '%s'"
+msgstr "Неочікувана відповідь схову: \"%s\""
+
+#, c-format
+msgid "Could not create directory for '%s'"
+msgstr "Не вдалося створити директорію для \"%s\""
+
+#, c-format
+msgid "Created autostash: %s\n"
+msgstr "Створено автосхов: %s\n"
+
+msgid "could not reset --hard"
+msgstr "не вдалося виконати скидання з --hard"
+
+#, c-format
+msgid "Applied autostash.\n"
+msgstr "Застосовано автосхов.\n"
+
+#, c-format
+msgid "cannot store %s"
+msgstr "неможливо зберегти %s"
+
+#, c-format
+msgid ""
+"%s\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
+msgstr ""
+"%s\n"
+"Ваші зміни в безпеці у схову.\n"
+"Ви можете запустити \"git stash pop\" або \"git stash drop\" у будь-який "
+"час.\n"
+
+msgid "Applying autostash resulted in conflicts."
+msgstr "Застосування автосхову призвело до конфліктів."
+
+msgid "Autostash exists; creating a new stash entry."
+msgstr "Автосхов існує; створення нового запису схову."
+
+msgid "could not detach HEAD"
+msgstr "не вдалося відʼєднати HEAD"
+
+#, c-format
+msgid "Stopped at HEAD\n"
+msgstr "Зупинено на HEAD\n"
+
+#, c-format
+msgid "Stopped at %s\n"
+msgstr "Зупинено на %s\n"
+
+#, c-format
+msgid ""
+"Could not execute the todo command\n"
+"\n"
+"    %.*s\n"
+"It has been rescheduled; To edit the command before continuing, please\n"
+"edit the todo list first:\n"
+"\n"
+"    git rebase --edit-todo\n"
+"    git rebase --continue\n"
+msgstr ""
+"Не вдалося виконати команду todo\n"
+"\n"
+"    %.*s\n"
+"Її було перенесено; Щоб відредагувати команду перед продовженням, будь "
+"ласка\n"
+"спочатку відредагуйте список справ:\n"
+"\n"
+"    git rebase --edit-todo\n"
+"    git rebase --continue\n"
+
+#, c-format
+msgid "Rebasing (%d/%d)%s"
+msgstr "Перебазування (%d/%d)%s"
+
+#, c-format
+msgid "Stopped at %s...  %.*s\n"
+msgstr "Зупинено на %s... %.*s\n"
+
+#, c-format
+msgid "unknown command %d"
+msgstr "невідома команда %d"
+
+msgid "could not read orig-head"
+msgstr "не вдалося прочитати orig-head"
+
+msgid "could not read 'onto'"
+msgstr "не вдалося прочитати  \"onto\""
+
+#, c-format
+msgid "could not update HEAD to %s"
+msgstr "не вдалося оновити HEAD до %s"
+
+#, c-format
+msgid "Successfully rebased and updated %s.\n"
+msgstr "Успішно перебазовано та оновлено %s.\n"
+
+msgid "cannot rebase: You have unstaged changes."
+msgstr "неможливо перебазувати: у вас є неіндексовані зміни."
+
+msgid "cannot amend non-existing commit"
+msgstr "неможливо виправити неіснуючий коміт"
+
+#, c-format
+msgid "invalid file: '%s'"
+msgstr "неприпустимий файл: \"%s\""
+
+#, c-format
+msgid "invalid contents: '%s'"
+msgstr "неприпустимий вміст: \"%s\""
+
+msgid ""
+"\n"
+"You have uncommitted changes in your working tree. Please, commit them\n"
+"first and then run 'git rebase --continue' again."
+msgstr ""
+"\n"
+"У вас є незакомічені зміни у вашому робочому дереві. Будь ласка, спочатку "
+"зробіть коміт,\n"
+"а потім знову виконайте \"git rebase --continue\"."
+
+#, c-format
+msgid "could not write file: '%s'"
+msgstr "не вдалося записати файл: \"%s\""
+
+msgid "could not remove CHERRY_PICK_HEAD"
+msgstr "не вдалося видалити CHERRY_PICK_HEAD"
+
+msgid "could not commit staged changes."
+msgstr "не вдалося записати індексовані зміни."
+
+#, c-format
+msgid "%s: can't cherry-pick a %s"
+msgstr "%s: неможливо зробити висмикування %s"
+
+#, c-format
+msgid "%s: bad revision"
+msgstr "%s: невірна ревізія"
+
+msgid "can't revert as initial commit"
+msgstr "неможливо зробити вивертання як початковий коміт"
+
+#, c-format
+msgid "skipped previously applied commit %s"
+msgstr "пропущено попередньо застосований коміт %s"
+
+msgid "use --reapply-cherry-picks to include skipped commits"
+msgstr "використовуйте --reapply-cherry-picks, щоб включити пропущені коміти"
+
+msgid "make_script: unhandled options"
+msgstr "make_script: необроблені опції"
+
+msgid "make_script: error preparing revisions"
+msgstr "make_script: помилка при підготовці ревізій"
+
+msgid "nothing to do"
+msgstr "нічого робити"
+
+msgid "could not skip unnecessary pick commands"
+msgstr "не вдалося пропустити непотрібні команди вибору"
+
+msgid "the script was already rearranged."
+msgstr "скрипт вже був перероблений."
+
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "файл update-refs за адресою \"%s\" є неприпустимим"
+
+#, c-format
+msgid "'%s' is outside repository at '%s'"
+msgstr "\"%s\" зовнішнє сховище в \"%s\""
+
+#, c-format
+msgid ""
+"%s: no such path in the working tree.\n"
+"Use 'git <command> -- <path>...' to specify paths that do not exist locally."
+msgstr ""
+"%s: немає такого шляху у робочому дереві.\n"
+"Використовуйте \"git <команда> -- <шлях>...\", щоб вказати шляхи, які не "
+"існують локально."
+
+#, c-format
+msgid ""
+"ambiguous argument '%s': unknown revision or path not in the working tree.\n"
+"Use '--' to separate paths from revisions, like this:\n"
+"'git <command> [<revision>...] -- [<file>...]'"
+msgstr ""
+"неоднозначний аргумент \"%s\": невідома ревізія або шлях не у робочому "
+"дереві.\n"
+"Використовуйте \"--\", щоб відокремити шлях від ревізій, наприклад, так:\n"
+"\"git <команда> [<ревізія>...] -- [<файл>...]\""
+
+#, c-format
+msgid "option '%s' must come before non-option arguments"
+msgstr "опція \"%s\" повинна стояти перед аргументами без опцій"
+
+#, c-format
+msgid ""
+"ambiguous argument '%s': both revision and filename\n"
+"Use '--' to separate paths from revisions, like this:\n"
+"'git <command> [<revision>...] -- [<file>...]'"
+msgstr ""
+"неоднозначний аргумент \"%s\": і ревізія, і назва файлу\n"
+"Використовуйте \"--\", щоб відокремити шляхи від ревізій, наприклад, так:\n"
+"\"git <команда> [<ревізія>...] -- [<файл>...]\""
+
+msgid "unable to set up work tree using invalid config"
+msgstr ""
+"не вдалося налаштувати робоче дерево, використовуючи неприпустиму "
+"конфігурацію"
+
+#, c-format
+msgid "Expected git repo version <= %d, found %d"
+msgstr "Очікувалось git сховищe версії <= %d, знайдено %d"
+
+msgid "unknown repository extension found:"
+msgid_plural "unknown repository extensions found:"
+msgstr[0] "знайдено невідомих розширень сховища:"
+msgstr[1] "знайдено невідомих розширень сховища:"
+msgstr[2] "знайдено невідомих розширень сховища:"
+
+msgid "repo version is 0, but v1-only extension found:"
+msgid_plural "repo version is 0, but v1-only extensions found:"
+msgstr[0] "версія сховища дорівнює 0, але знайдено v1-only розширень:"
+msgstr[1] "версія сховища дорівнює 0, але знайдено v1-only розширень:"
+msgstr[2] "версія сховища дорівнює 0, але знайдено v1-only розширень:"
+
+#, c-format
+msgid "error opening '%s'"
+msgstr "помилка при відкритті \"%s\""
+
+#, c-format
+msgid "too large to be a .git file: '%s'"
+msgstr "занадто великий для .git-файлу: \"%s\""
+
+#, c-format
+msgid "error reading %s"
+msgstr "помилка зчитування %s"
+
+#, c-format
+msgid "invalid gitfile format: %s"
+msgstr "неприпустимий формат git файлу: %s"
+
+#, c-format
+msgid "no path in gitfile: %s"
+msgstr "немає шляху в gitfile: %s"
+
+#, c-format
+msgid "not a git repository: %s"
+msgstr "не є git сховищем: %s"
+
+#, c-format
+msgid "'$%s' too big"
+msgstr "\"$%s\" занадто великий"
+
+#, c-format
+msgid "not a git repository: '%s'"
+msgstr "не є git сховищем: \"%s\""
+
+#, c-format
+msgid "cannot chdir to '%s'"
+msgstr "неможливо змінити директорію на \"%s\""
+
+msgid "cannot come back to cwd"
+msgstr "неможливо повернутися до поточної робочої директорії"
+
+#, c-format
+msgid "failed to stat '%*s%s%s'"
+msgstr "не вдалося записати \"%*s%s%s\""
+
+msgid "Unable to read current working directory"
+msgstr "Не вдалося прочитати поточну робочу директорію"
+
+#, c-format
+msgid "cannot change to '%s'"
+msgstr "неможливо змінити на \"%s\""
+
+#, c-format
+msgid "not a git repository (or any of the parent directories): %s"
+msgstr "не є git сховищем (як і жодна з батьківських директорій): %s"
+
+#, c-format
+msgid ""
+"not a git repository (or any parent up to mount point %s)\n"
+"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
+msgstr ""
+"не є git сховищем (як і жодна з батьківських директорій до місця монтування "
+"%s)\n"
+"Зупинка на межі файлової системи (GIT_DISCOVERY_ACROSS_FILESYSTEM не "
+"встановлено)."
+
+#, c-format
+msgid ""
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+msgstr ""
+"виявлено сумнівне право власності у сховищі за адресою \"%s\"\n"
+"%sЩоб додати виняток для цієї директорії, виконайте:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr ""
+"неможливо використати порожнє сховище \"%s\" (safe.bareRepository "
+"встановлено в \"%s\")"
+
+#, c-format
+msgid ""
+"problem with core.sharedRepository filemode value (0%.3o).\n"
+"The owner of files must always have read and write permissions."
+msgstr ""
+"проблема зі значенням файлового режиму core.sharedRepository (0%.3o).\n"
+"Власник файлів завжди повинен мати дозвіл на читання та запис."
+
+msgid "fork failed"
+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 "індексний запис є директорією, але не є розрідженим (%08x)"
+
+msgid "cannot use split index with a sparse index"
+msgstr "не можна використовувати розщеплений індекс з розрідженим індексом"
+
+#, c-format
+msgid "%u.%2.2u GiB"
+msgstr "%u.%2.2u ГіБ"
+
+#, c-format
+msgid "%u.%2.2u GiB/s"
+msgstr "%u.%2.2u ГіБ/с"
+
+#, c-format
+msgid "%u.%2.2u MiB"
+msgstr "%u.%2.2u МіБ"
+
+#, c-format
+msgid "%u.%2.2u MiB/s"
+msgstr "%u.%2.2u МіБ/с"
+
+#, c-format
+msgid "%u.%2.2u KiB"
+msgstr "%u.%2.2u КіБ"
+
+#, c-format
+msgid "%u.%2.2u KiB/s"
+msgstr "%u.%2.2u КіБ/с"
+
+#, c-format
+msgid "%u byte"
+msgid_plural "%u bytes"
+msgstr[0] "%u байт"
+msgstr[1] "%u байти"
+msgstr[2] "%u байтів"
+
+#, c-format
+msgid "%u byte/s"
+msgid_plural "%u bytes/s"
+msgstr[0] "%u байт/s"
+msgstr[1] "%u байти/s"
+msgstr[2] "%u байтів/s"
+
+#, c-format
+msgid "ignoring suspicious submodule name: %s"
+msgstr "ігнорування підозрілої назви підмодуля: %s"
+
+msgid "negative values not allowed for submodule.fetchJobs"
+msgstr "негативні значення не дозволені для submodule.fetchJobs"
+
+#, c-format
+msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
+msgstr ""
+"ігнорування \"%s\", який може бути інтерпретований як параметр командного "
+"рядка: %s"
+
+#, c-format
+msgid "Could not update .gitmodules entry %s"
+msgstr "Не вдалося оновити запис %s у .gitmodules"
+
+msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
+msgstr ""
+"Неможливо змінити не злиті .gitmodules, спочатку розвʼяжіть конфлікти злиття"
+
+#, c-format
+msgid "Could not find section in .gitmodules where path=%s"
+msgstr "Не вдалося знайти розділ у .gitmodules де path=%s"
+
+#, c-format
+msgid "Could not remove .gitmodules entry for %s"
+msgstr "Не вдалося видалити запис .gitmodules для %s"
+
+msgid "staging updated .gitmodules failed"
+msgstr "індексація оновленого .gitmodules завершилася невдало"
+
+#, c-format
+msgid "in unpopulated submodule '%s'"
+msgstr "у незаповненому підмодулі \"%s\""
+
+#, c-format
+msgid "Pathspec '%s' is in submodule '%.*s'"
+msgstr "Визначник шляху \"%s\" знаходиться у підмодулі \"%.*s\""
+
+#, c-format
+msgid "bad --ignore-submodules argument: %s"
+msgstr "невірний --ignore-submodules аргумент: %s"
+
+#, c-format
+msgid ""
+"Submodule in commit %s at path: '%s' collides with a submodule named the "
+"same. Skipping it."
+msgstr ""
+"Підмодуль у коміті %s за шляхом \"%s\" зіткнувся з підмодулем з такою самою "
+"назвою. Пропускаємо його."
+
+#, c-format
+msgid "submodule entry '%s' (%s) is a %s, not a commit"
+msgstr "запис підмодуля \"%s\" (%s) є %s, а не комітом"
+
+#, c-format
+msgid ""
+"Could not run 'git rev-list <commits> --not --remotes -n 1' command in "
+"submodule %s"
+msgstr ""
+"Не вдалося виконати команду \"git rev-list <коміти> --not --remotes -n 1\" у "
+"підмодулі %s"
+
+#, c-format
+msgid "process for submodule '%s' failed"
+msgstr "процес для підмодуля \"%s\" завершився невдало"
+
+#, c-format
+msgid "Pushing submodule '%s'\n"
+msgstr "Надсилання підмодуля \"%s\"\n"
+
+#, c-format
+msgid "Unable to push submodule '%s'\n"
+msgstr "Не вдалося надіслати підмодуль \"%s\"\n"
+
+#, c-format
+msgid "Fetching submodule %s%s\n"
+msgstr "Отримання підмодуля %s%s\n"
+
+#, c-format
+msgid "Could not access submodule '%s'\n"
+msgstr "Не вдалося отримати доступ до підмодуля \"%s\"\n"
+
+#, c-format
+msgid "Could not access submodule '%s' at commit %s\n"
+msgstr "Не вдалося отримати доступ до підмодуля \"%s\" для коміту %s\n"
+
+#, c-format
+msgid "Fetching submodule %s%s at commit %s\n"
+msgstr "Отримання підмодуля %s%s для коміту %s\n"
+
+#, c-format
+msgid ""
+"Errors during submodule fetch:\n"
+"%s"
+msgstr ""
+"Помилки під час отримання підмодуля:\n"
+"%s"
+
+#, c-format
+msgid "'%s' not recognized as a git repository"
+msgstr "\"%s\" не розпізнано як git сховище"
+
+#, c-format
+msgid "Could not run 'git status --porcelain=2' in submodule %s"
+msgstr ""
+"Не вдалося виконати команду \"git status --porcelain=2\" у підмодулі %s"
+
+#, c-format
+msgid "'git status --porcelain=2' failed in submodule %s"
+msgstr "\"git status --porcelain=2\" завершився невдало у підмодулі %s"
+
+#, c-format
+msgid "could not start 'git status' in submodule '%s'"
+msgstr "не вдалося запустити \"git status\" у підмодулі \"%s\""
+
+#, c-format
+msgid "could not run 'git status' in submodule '%s'"
+msgstr "не вдалося запустити \"git status\" у підмодулі \"%s\""
+
+#, c-format
+msgid "Could not unset core.worktree setting in submodule '%s'"
+msgstr "Не вдалося скинути налаштування core.worktree у підмодулі \"%s\""
+
+#, c-format
+msgid "could not recurse into submodule '%s'"
+msgstr "не вдалося рекурсивно перейти в підмодуль \"%s\""
+
+msgid "could not reset submodule index"
+msgstr "не вдалося скинути індекс підмодуля"
+
+#, c-format
+msgid "submodule '%s' has dirty index"
+msgstr "підмодуль \"%s\" має брудний індекс"
+
+#, c-format
+msgid "Submodule '%s' could not be updated."
+msgstr "Не вдалося оновити підмодуль \"%s\"."
+
+#, c-format
+msgid "submodule git dir '%s' is inside git dir '%.*s'"
+msgstr "підмодуль git dir \"%s\" знаходиться всередині git директорії \"%.*s\""
+
+#, c-format
+msgid ""
+"relocate_gitdir for submodule '%s' with more than one worktree not supported"
+msgstr ""
+"relocate_gitdir для підмодуля \"%s\" з більш ніж одним робочим деревом не "
+"підтримується"
+
+#, c-format
+msgid "could not lookup name for submodule '%s'"
+msgstr "не вдалося знайти назву для підмодуля \"%s\""
+
+#, c-format
+msgid "refusing to move '%s' into an existing git dir"
+msgstr "відмовлено в переміщенні \"%s\" до існуючої git директорії"
+
+#, c-format
+msgid ""
+"Migrating git directory of '%s%s' from\n"
+"'%s' to\n"
+"'%s'\n"
+msgstr ""
+"Міграція git-директорії \"%s%s\" з\n"
+"\"%s\" до\n"
+"\"%s\"\n"
+
+msgid "could not start ls-files in .."
+msgstr "не вдалося запустити ls-файли в .."
+
+#, c-format
+msgid "ls-tree returned unexpected return code %d"
+msgstr "ls-tree повернув неочікуваний код повернення %d"
+
+#, c-format
+msgid "failed to lstat '%s'"
+msgstr "не вдалося виконати lstat для \"%s\""
+
+msgid "no remote configured to get bundle URIs from"
+msgstr ""
+"немає налаштованого віддаленого призначення для отримання URI пакунків з "
+"нього"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "віддалений \"%s\" не має налаштованої URL-адреси"
+
+msgid "could not get the bundle-uri list"
+msgstr "не вдалося отримати список bundle-uri"
+
+msgid "test-tool cache-tree <options> (control|prime|update)"
+msgstr "test-tool cache-tree <опції> (control|prime|update)"
+
+msgid "clear the cache tree before each iteration"
+msgstr "очищати дерево кешу перед кожною ітерацією"
+
+msgid "number of entries in the cache tree to invalidate (default 0)"
+msgstr ""
+"кількість записів у дереві кешу, які потрібно анулювати (за замовчуванням 0)"
+
+msgid "unhandled options"
+msgstr "необроблені опції"
+
+msgid "error preparing revisions"
+msgstr "помилка при підготовці ревізій"
+
+#, c-format
+msgid "commit %s is not marked reachable"
+msgstr "коміт %s не позначений як досяжний"
+
+msgid "too many commits marked reachable"
+msgstr "забагато комітів позначено як досяжні"
+
+msgid "test-tool serve-v2 [<options>]"
+msgstr "test-tool serve-v2 [<опції>]"
+
+msgid "exit immediately after advertising capabilities"
+msgstr "вихід відразу після показу здібностей"
+
+msgid "test-helper simple-ipc is-active    [<name>] [<options>]"
+msgstr "test-helper simple-ipc is-active    [<назва>] [<опції>]"
+
+msgid "test-helper simple-ipc run-daemon   [<name>] [<threads>]"
+msgstr "test-helper simple-ipc run-daemon   [<назва>] [<потоки>]"
+
+msgid "test-helper simple-ipc start-daemon [<name>] [<threads>] [<max-wait>]"
+msgstr ""
+"test-helper simple-ipc start-daemon [<назва>] [<потоки>] [<максимальний час "
+"очікування>]"
+
+msgid "test-helper simple-ipc stop-daemon  [<name>] [<max-wait>]"
+msgstr ""
+"test-helper simple-ipc stop-daemon  [<назва>] [<максимальний час очікування>]"
+
+msgid "test-helper simple-ipc send         [<name>] [<token>]"
+msgstr "test-helper simple-ipc send         [<назва>] [<токен>]"
+
+msgid "test-helper simple-ipc sendbytes    [<name>] [<bytecount>] [<byte>]"
+msgstr ""
+"test-helper simple-ipc sendbytes    [<назва>] [<кількість байт>] [<байт>]"
+
+msgid ""
+"test-helper simple-ipc multiple     [<name>] [<threads>] [<bytecount>] "
+"[<batchsize>]"
+msgstr ""
+"test-helper simple-ipc multiple     [<назва>] [<потоки>] [<кількість байт>] "
+"[<розмір пакетів>]"
+
+msgid "name or pathname of unix domain socket"
+msgstr "назва або назва шляху сокета домену unix"
+
+msgid "named-pipe name"
+msgstr "назва іменованого канала"
+
+msgid "number of threads in server thread pool"
+msgstr "кількість потоків у пулі потоків сервера"
+
+msgid "seconds to wait for daemon to start or stop"
+msgstr "секунд чекати на запуск або зупинку демона"
+
+msgid "number of bytes"
+msgstr "кількість байтів"
+
+msgid "number of requests per thread"
+msgstr "кількість запитів на потік"
+
+msgid "byte"
+msgstr "байт"
+
+msgid "ballast character"
+msgstr "баластний символ"
+
+msgid "token"
+msgstr "токен"
+
+msgid "command token to send to the server"
+msgstr "токен команди для відправки на сервер"
+
+#, c-format
+msgid "running trailer command '%s' failed"
+msgstr "не вдалося виконати команду трейлера \"%s\""
+
+#, c-format
+msgid "unknown value '%s' for key '%s'"
+msgstr "невідоме значення \"%s\" для ключа \"%s\""
+
+#, c-format
+msgid "empty trailer token in trailer '%.*s'"
+msgstr "порожній токен трейлера в трейлері \"%.*s\""
+
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "не вдалося прочитати вхідний файл \"%s\""
+
+#, c-format
+msgid "could not stat %s"
+msgstr "не вдалося прочитати %s"
+
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "файл %s не є звичайним файлом"
+
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "файл %s не доступний для запису користувачем"
+
+msgid "could not open temporary file"
+msgstr "не вдалося відкрити тимчасовий файл"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "не вдалося перейменувати тимчасовий файл на %s"
+
+msgid "full write to remote helper failed"
+msgstr "не вдалося виконати повний запис до віддаленого помічника"
+
+#, c-format
+msgid "unable to find remote helper for '%s'"
+msgstr "не вдалося знайти віддаленого помічника для \"%s\""
+
+msgid "can't dup helper output fd"
+msgstr "неможливо зробити копію дескриптора файла виводу помічника"
+
+#, c-format
+msgid ""
+"unknown mandatory capability %s; this remote helper probably needs newer "
+"version of Git"
+msgstr ""
+"невідома обовʼязкова здібність %s; цей віддалений помічник напевно потребує "
+"новішої версії Git"
+
+msgid "this remote helper should implement refspec capability"
+msgstr "цей віддалений помічник має реалізовувати здібність refspec"
+
+#, c-format
+msgid "%s unexpectedly said: '%s'"
+msgstr "%s несподівано сказав: \"%s\""
+
+#, c-format
+msgid "%s also locked %s"
+msgstr "%s також заблокувало %s"
+
+msgid "couldn't run fast-import"
+msgstr "не вдалося запустити fast-import"
+
+msgid "error while running fast-import"
+msgstr "помилка під час виконання швидкого імпорту"
+
+#, c-format
+msgid "could not read ref %s"
+msgstr "не вдалося прочитати посилання %s"
+
+#, c-format
+msgid "unknown response to connect: %s"
+msgstr "невідома відповідь на зʼєднання: %s"
+
+msgid "setting remote service path not supported by protocol"
+msgstr "встановлення шляху до віддаленого сервісу не підтримується протоколом"
+
+msgid "invalid remote service path"
+msgstr "неприпустимий шлях до віддаленої служби"
+
+msgid "operation not supported by protocol"
+msgstr "операція не підтримується протоколом"
+
+#, c-format
+msgid "can't connect to subservice %s"
+msgstr "неможливо підключитися до підсервісу %s"
+
+msgid "--negotiate-only requires protocol v2"
+msgstr "--negotiate-only потребує протоколу v2"
+
+msgid "'option' without a matching 'ok/error' directive"
+msgstr "\"option\" без відповідної директиви \"ok/error\""
+
+#, c-format
+msgid "expected ok/error, helper said '%s'"
+msgstr "очікувалось ok/error, помічник сказав \"%s\""
+
+#, c-format
+msgid "helper reported unexpected status of %s"
+msgstr "helper повідомив про неочікуваний статус %s"
+
+#, c-format
+msgid "helper %s does not support dry-run"
+msgstr "помічник %s не підтримує dry-run"
+
+#, c-format
+msgid "helper %s does not support --signed"
+msgstr "помічник %s не підтримує --signed"
+
+#, c-format
+msgid "helper %s does not support --signed=if-asked"
+msgstr "помічник %s не підтримує --signed=if-asked"
+
+#, c-format
+msgid "helper %s does not support --atomic"
+msgstr "помічник %s не підтримує --atomic"
+
+#, c-format
+msgid "helper %s does not support --%s"
+msgstr "помічник %s не підтримує --%s"
+
+#, c-format
+msgid "helper %s does not support 'push-option'"
+msgstr "помічник %s не підтримує \"push-option\""
+
+msgid "remote-helper doesn't support push; refspec needed"
+msgstr "remote-helper не підтримує push; потрібен refspec"
+
+#, c-format
+msgid "helper %s does not support 'force'"
+msgstr "помічник %s не підтримує \"force\""
+
+msgid "couldn't run fast-export"
+msgstr "не вдалося запустити fast-export"
+
+msgid "error while running fast-export"
+msgstr "помилка під час виконання швидкого експорту"
+
+#, c-format
+msgid ""
+"No refs in common and none specified; doing nothing.\n"
+"Perhaps you should specify a branch.\n"
+msgstr ""
+"Немає спільних посилань і жодного не вказано; нічого не робиться.\n"
+"Можливо, вам слід вказати гілку.\n"
+
+#, c-format
+msgid "unsupported object format '%s'"
+msgstr "непідтримуваний обʼєкт формата \"%s\""
+
+#, c-format
+msgid "malformed response in ref list: %s"
+msgstr "невірно сформована відповідь у списку посилань: %s"
+
+#, c-format
+msgid "read(%s) failed"
+msgstr "read(%s) завершився невдало"
+
+#, c-format
+msgid "write(%s) failed"
+msgstr "write(%s) завершився невдало"
+
+#, c-format
+msgid "%s thread failed"
+msgstr "%s потік завершився невдало"
+
+#, c-format
+msgid "%s thread failed to join: %s"
+msgstr "%s потік не зміг приєднатись: %s"
+
+#, c-format
+msgid "can't start thread for copying data: %s"
+msgstr "неможливо запустити потік для копіювання даних: %s"
+
+#, c-format
+msgid "%s process failed to wait"
+msgstr "%s процес не зміг дочекатися"
+
+#, c-format
+msgid "%s process failed"
+msgstr "%s процес завершився невдало"
+
+msgid "can't start thread for copying data"
+msgstr "неможливо запустити потік для копіювання даних"
+
+#, c-format
+msgid "Would set upstream of '%s' to '%s' of '%s'\n"
+msgstr "Встановить першоджерельне сховище для \"%s\" на \"%s\" в \"%s\"\n"
+
+#, c-format
+msgid "could not read bundle '%s'"
+msgstr "не вдалося прочитати пакунок \"%s\""
+
+#, c-format
+msgid "transport: invalid depth option '%s'"
+msgstr "transport: неприпустимий параметр глибини \"%s\""
+
+msgid "see protocol.version in 'git help config' for more details"
+msgstr ""
+"дивіться protocol.version у \"git help config\" для більш детальної "
+"інформації"
+
+msgid "server options require protocol version 2 or later"
+msgstr "опції сервера вимагають протокол версії 2 або пізнішої"
+
+msgid "server does not support wait-for-done"
+msgstr "сервер не підтримує wait-for-done"
+
+msgid "could not parse transport.color.* config"
+msgstr "не вдалося розібрати конфігурацію transport.color.*"
+
+msgid "support for protocol v2 not implemented yet"
+msgstr "підтримка протоколу v2 ще не запроваджена"
+
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "невідоме значення для конфігурації \"%s\": %s"
+
+#, c-format
+msgid "transport '%s' not allowed"
+msgstr "засіб передачі \"%s\" не дозволений"
+
+msgid "git-over-rsync is no longer supported"
+msgstr "git-over-rsync більше не підтримується"
+
+#, c-format
+msgid ""
+"The following submodule paths contain changes that can\n"
+"not be found on any remote:\n"
+msgstr ""
+"Наступні шляхи до підмодулів містять зміни, які неможливо\n"
+"знайти в жодному віддаленому призначенні:\n"
+
+#, c-format
+msgid ""
+"\n"
+"Please try\n"
+"\n"
+"\tgit push --recurse-submodules=on-demand\n"
+"\n"
+"or cd to the path and use\n"
+"\n"
+"\tgit push\n"
+"\n"
+"to push them to a remote.\n"
+"\n"
+msgstr ""
+"\n"
+"Будь ласка, спробуйте\n"
+"\n"
+"\tgit push --recurse-submodules=on-demand\n"
+"\n"
+"або перейдіть до директорії та використайте\n"
+"\n"
+"\tgit push\n"
+"\n"
+"щоб надіслати їх до віддаленого призначення.\n"
+
+msgid "Aborting."
+msgstr "Відміна."
+
+msgid "failed to push all needed submodules"
+msgstr "не вдалося надіслати всі необхідні підмодулі"
+
+msgid "bundle-uri operation not supported by protocol"
+msgstr "bundle-uri операція не підтримується протоколом"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "не вдалося отримати список адрес пакетів, оголошений сервером"
+
+msgid "too-short tree object"
+msgstr "занадто короткий обʼєкт дерева"
+
+msgid "malformed mode in tree entry"
+msgstr "невірно визначений режим у записі дерева"
+
+msgid "empty filename in tree entry"
+msgstr "порожня назва файлу у записі дерева"
+
+msgid "too-short tree file"
+msgstr "занадто короткий файл дерева"
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by checkout:\n"
+"%%sPlease commit your changes or stash them before you switch branches."
+msgstr ""
+"Ваші локальні зміни в наступних файлах будуть перезаписані при переключенні "
+"стану:\n"
+"%%sБудь ласка, зробіть коміт або додайте їх до схову перед переходом до "
+"іншої гілки."
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by checkout:\n"
+"%%s"
+msgstr ""
+"Ваші локальні зміни в наступних файлах будуть перезаписані при переключенні "
+"стану:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"%%sPlease commit your changes or stash them before you merge."
+msgstr ""
+"Ваші локальні зміни у наступних файлах будуть перезаписані під час злиття:\n"
+"%%sБудь ласка, зробіть коміт або додайте їх до схову перед злиттям."
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"%%s"
+msgstr ""
+"Ваші локальні зміни у наступних файлах будуть перезаписані під час злиття:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by %s:\n"
+"%%sPlease commit your changes or stash them before you %s."
+msgstr ""
+"Ваші локальні зміни у наступних файлах будуть перезаписані %s:\n"
+"%%sБудь ласка, зробіть коміт або додайте їх до схову перед %s."
+
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by %s:\n"
+"%%s"
+msgstr ""
+"Ваші локальні зміни у наступних файлах будуть перезаписані %s:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"Updating the following directories would lose untracked files in them:\n"
+"%s"
+msgstr ""
+"Оновлення наступних директорій призведе до втрати невідстежуваних файлів у "
+"цих директоріях:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Refusing to remove the current working directory:\n"
+"%s"
+msgstr ""
+"Відмовлено у видаленні поточної робочої директорії:\n"
+"%s"
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be removed by checkout:\n"
+"%%sPlease move or remove them before you switch branches."
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть видалені під час "
+"переключення:\n"
+"%%sБудь ласка, перемістіть або видаліть їх перед переходом до іншої гілки."
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be removed by checkout:\n"
+"%%s"
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть видалені під час "
+"переключення:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be removed by merge:\n"
+"%%sPlease move or remove them before you merge."
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть видалені при виконанні "
+"злиття:\n"
+"%%sБудь ласка, перемістіть або видаліть їх перед злиттям."
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be removed by merge:\n"
+"%%s"
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть видалені при виконанні "
+"злиття:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be removed by %s:\n"
+"%%sPlease move or remove them before you %s."
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть видалені при виконанні "
+"%s:\n"
+"%%sБудь ласка, перемістіть або видаліть їх перед %s."
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be removed by %s:\n"
+"%%s"
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть видалені при виконанні "
+"%s:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be overwritten by "
+"checkout:\n"
+"%%sPlease move or remove them before you switch branches."
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть перезаписані при "
+"переключенні стану\n"
+"%%sБудь ласка, перемістіть або видаліть їх перед переходом до іншої гілки."
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be overwritten by "
+"checkout:\n"
+"%%s"
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть перезаписані при "
+"переключенні стану:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be overwritten by merge:\n"
+"%%sPlease move or remove them before you merge."
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть перезаписані при "
+"злитті:\n"
+"%%sБудь ласка, перемістіть або видаліть їх перед злиттям."
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be overwritten by merge:\n"
+"%%s"
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть перезаписані при "
+"виконанні злиття:\n"
+"%%s"
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be overwritten by %s:\n"
+"%%sPlease move or remove them before you %s."
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть перезаписані %s:\n"
+"%%sБудь ласка, перемістіть або видаліть їх перед %s."
+
+#, c-format
+msgid ""
+"The following untracked working tree files would be overwritten by %s:\n"
+"%%s"
+msgstr ""
+"Наступні невідстежувані файли робочого дерева будуть перезаписані %s:\n"
+"%%s"
+
+#, c-format
+msgid "Entry '%s' overlaps with '%s'.  Cannot bind."
+msgstr "Запис \"%s\" перетинається з \"%s\".  Неможливо звʼязати."
+
+#, c-format
+msgid ""
+"Cannot update submodule:\n"
+"%s"
+msgstr ""
+"Не вдалося оновити підмодуль:\n"
+"%s"
+
+#, c-format
+msgid ""
+"The following paths are not up to date and were left despite sparse "
+"patterns:\n"
+"%s"
+msgstr ""
+"Наступні шляхи не є актуальними і були залишені, незважаючи на розріджені "
+"шаблони:\n"
+"%s"
+
+#, c-format
+msgid ""
+"The following paths are unmerged and were left despite sparse patterns:\n"
+"%s"
+msgstr ""
+"Наступні шляхи не злиті і були залишені, незважаючи на розріджені шаблони:\n"
+"%s"
+
+#, c-format
+msgid ""
+"The following paths were already present and thus not updated despite sparse "
+"patterns:\n"
+"%s"
+msgstr ""
+"Наступні шляхи вже існували і тому не були оновлені, незважаючи на "
+"розріджені шаблони:\n"
+"%s"
+
+#, c-format
+msgid "Aborting\n"
+msgstr "Переривання\n"
+
+#, c-format
+msgid ""
+"After fixing the above paths, you may want to run `git sparse-checkout "
+"reapply`.\n"
+msgstr ""
+"Після виправлення наведених вище шляхів можливо ви забажаєте виконати \"git "
+"sparse-checkout reapply\".\n"
+
+msgid "Updating files"
+msgstr "Оновлення файлів"
+
+msgid ""
+"the following paths have collided (e.g. case-sensitive paths\n"
+"on a case-insensitive filesystem) and only one from the same\n"
+"colliding group is in the working tree:\n"
+msgstr ""
+"зіткнулися наступні шляхи (наприклад, шляхи, чутливі до регістру\n"
+"у файловій системі, не чутливій до регістру) і лише один шлях з тієї \n"
+"групи, що зіткнулися, знаходиться у робочому дереві:\n"
+
+msgid "Updating index flags"
+msgstr "Оновлення прапорців індексу"
+
+#, c-format
+msgid "worktree and untracked commit have duplicate entries: %s"
+msgstr "робоче дерево та невідстежуваний коміт мають дубльовані записи: %s"
+
+msgid "expected flush after fetch arguments"
+msgstr "очікувалось flush після аргументів отримання"
+
+msgid "invalid URL scheme name or missing '://' suffix"
+msgstr "неприпустима назва схеми URL-адреси або відсутній \"://\" суфікс"
+
+#, c-format
+msgid "invalid %XX escape sequence"
+msgstr "неприпустима %XX екрануюча послідовність"
+
+msgid "missing host and scheme is not 'file:'"
+msgstr "відсутній хост і схема не \"file:\""
+
+msgid "a 'file:' URL may not have a port number"
+msgstr "\"file:\" URL-адреса не може мати номера порту"
+
+msgid "invalid characters in host name"
+msgstr "неприпустимі символи в назві хоста"
+
+msgid "invalid port number"
+msgstr "неприпустимий номер порту"
+
+msgid "invalid '..' path segment"
+msgstr "неприпустимий \"..\" сегмент шляху"
+
+msgid "usage: "
+msgstr "використання: "
+
+msgid "fatal: "
+msgstr "збій: "
+
+msgid "error: "
+msgstr "помилка: "
+
+msgid "warning: "
+msgstr "попередження: "
+
+msgid "Fetching objects"
+msgstr "Отримання обʼєктів"
+
+#, c-format
+msgid "'%s' at main working tree is not the repository directory"
+msgstr "\"%s\" у головному робочому дереві не є директорією сховища"
+
+#, c-format
+msgid "'%s' file does not contain absolute path to the working tree location"
+msgstr ""
+"\"%s\" файл не містить абсолютного шляху до розташування робочого дерева"
+
+#, c-format
+msgid "'%s' is not a .git file, error code %d"
+msgstr "\"%s\" не є .git файлом, код помилки %d"
+
+#, c-format
+msgid "'%s' does not point back to '%s'"
+msgstr "\"%s\" не вказує назад на \"%s\""
+
+msgid "not a directory"
+msgstr "не є директорією"
+
+msgid ".git is not a file"
+msgstr ".git не є файлом"
+
+msgid ".git file broken"
+msgstr ".git файл пошкоджено"
+
+msgid ".git file incorrect"
+msgstr ".git файл не є коректним"
+
+msgid "not a valid path"
+msgstr "неприпустимий шлях"
+
+msgid "unable to locate repository; .git is not a file"
+msgstr "не вдалося знайти сховище; .git не є файлом"
+
+msgid "unable to locate repository; .git file does not reference a repository"
+msgstr "не вдалося знайти сховище; .git-файл не посилається на сховище"
+
+msgid "unable to locate repository; .git file broken"
+msgstr "не вдалося знайти сховище; файл .git пошкоджено"
+
+msgid "gitdir unreadable"
+msgstr "нечитабельна git директорія"
+
+msgid "gitdir incorrect"
+msgstr "невірна git директорія"
+
+msgid "not a valid directory"
+msgstr "неприпустима директорія"
+
+msgid "gitdir file does not exist"
+msgstr "файл git директорії не існує"
+
+#, c-format
+msgid "unable to read gitdir file (%s)"
+msgstr "не вдалося прочитати файл git директорії (%s)"
+
+#, c-format
+msgid "short read (expected %<PRIuMAX> bytes, read %<PRIuMAX>)"
+msgstr ""
+"помилка при зчитуванні (очікувалось %<PRIuMAX> байтів, прочитано %<PRIuMAX>)"
+
+msgid "invalid gitdir file"
+msgstr "неприпустимий файл git директорії"
+
+msgid "gitdir file points to non-existent location"
+msgstr "файл git директорії вказує на неіснуюче розташування"
+
+#, c-format
+msgid "unable to set %s in '%s'"
+msgstr "не вдалося встановити %s в \"%s\""
+
+#, c-format
+msgid "unable to unset %s in '%s'"
+msgstr "не вдалося скинути %s в \"%s\""
+
+msgid "failed to set extensions.worktreeConfig setting"
+msgstr "не вдалося встановити extensions.worktreeConfig параметр"
+
+#, c-format
+msgid "could not setenv '%s'"
+msgstr "не вдалося встановити змінну оточення \"%s\""
+
+#, c-format
+msgid "unable to create '%s'"
+msgstr "не вдалося створити \"%s\""
+
+#, c-format
+msgid "could not open '%s' for reading and writing"
+msgstr "не вдалося відкрити \"%s\" для читання та запису"
+
+#, c-format
+msgid "unable to access '%s'"
+msgstr "не вдалося отримати доступ до \"%s\""
+
+msgid "unable to get current working directory"
+msgstr "не вдалося завантажити поточну робочу директорію"
+
+msgid "Unmerged paths:"
+msgstr "не злиті шляхи:"
+
+msgid "  (use \"git restore --staged <file>...\" to unstage)"
+msgstr ""
+"  (використовуйте \"git restore --staged <файл>...\", щоб видалити з індексу)"
+
+#, c-format
+msgid "  (use \"git restore --source=%s --staged <file>...\" to unstage)"
+msgstr ""
+"  (використовуйте \"git restore --source=%s --staged <file>...\", щоб "
+"прибрати з індексу)"
+
+msgid "  (use \"git rm --cached <file>...\" to unstage)"
+msgstr ""
+"  (використовуйте \"git rm --cached <file>...\", щоб видалити з індексу)"
+
+msgid "  (use \"git add <file>...\" to mark resolution)"
+msgstr "  (використовуйте \"git add <файл>...\", щоб позначити як розвʼязане)"
+
+msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr ""
+"  (використовуйте \"git add/rm <файл>...\" за потребою, щоб позначити "
+"вирішення)"
+
+msgid "  (use \"git rm <file>...\" to mark resolution)"
+msgstr "  (використовуйте \"git rm <файл>...\", щоб позначити вирішення)"
+
+msgid "Changes to be committed:"
+msgstr "Зміни, додані до майбутнього коміту:"
+
+msgid "Changes not staged for commit:"
+msgstr "Зміни, не додані до майбутнього коміту:"
+
+msgid "  (use \"git add <file>...\" to update what will be committed)"
+msgstr "  (скористайтесь \"git add <файл>...\", щоб оновити майбутній коміт)"
+
+msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr ""
+"  (скористайтесь \"git add/rm <файл>...\", щоб оновити майбутній коміт)"
+
+msgid ""
+"  (use \"git restore <file>...\" to discard changes in working directory)"
+msgstr ""
+"  (скористайтесь \"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 <файл>...\", щоб додати до майбутнього коміту)"
+
+msgid "both deleted:"
+msgstr "видалено обома:"
+
+msgid "added by us:"
+msgstr "додано нами:"
+
+msgid "deleted by them:"
+msgstr "видалено ними:"
+
+msgid "added by them:"
+msgstr "додано ними:"
+
+msgid "deleted by us:"
+msgstr "видалено нами:"
+
+msgid "both added:"
+msgstr "додано обома:"
+
+msgid "both modified:"
+msgstr "змінено обома:"
+
+msgid "new file:"
+msgstr "новий файл:"
+
+msgid "copied:"
+msgstr "скопійовано:"
+
+msgid "deleted:"
+msgstr "видалено:"
+
+msgid "modified:"
+msgstr "змінено:"
+
+msgid "renamed:"
+msgstr "перейменовано:"
+
+msgid "typechange:"
+msgstr "змінено тип:"
+
+msgid "unknown:"
+msgstr "невідомо:"
+
+msgid "unmerged:"
+msgstr "не злито:"
+
+msgid "new commits, "
+msgstr "нові коміти, "
+
+msgid "modified content, "
+msgstr "змінений контент, "
+
+msgid "untracked content, "
+msgstr "невідстежуваний контент, "
+
+#, c-format
+msgid "Your stash currently has %d entry"
+msgid_plural "Your stash currently has %d entries"
+msgstr[0] "У вашій схованці наразі є %d запис"
+msgstr[1] "У вашій схованці наразі є %d записи"
+msgstr[2] "У вашій схованці наразі є %d записів"
+
+msgid "Submodules changed but not updated:"
+msgstr "Підмодулі змінено, але не оновлено:"
+
+msgid "Submodule changes to be committed:"
+msgstr "Зміни в підмодулі, які будуть закомічені:"
+
+msgid ""
+"Do not modify or remove the line above.\n"
+"Everything below it will be ignored."
+msgstr ""
+"Не змінюйте та не видаляйте рядок вище.\n"
+"Все, що нижче, буде проігноровано."
+
+#, c-format
+msgid ""
+"\n"
+"It took %.2f seconds to compute the branch ahead/behind values.\n"
+"You can use '--no-ahead-behind' to avoid this.\n"
+msgstr ""
+"\n"
+"Обчислення значень попереду/позаду для гілки зайняло %.2f секунд.\n"
+"Ви можете використати параметр '--no-ahead-behind', щоб уникнути цього.\n"
+
+msgid "You have unmerged paths."
+msgstr "У вас є не злиті шляхи."
+
+msgid "  (fix conflicts and run \"git commit\")"
+msgstr "  (виправте конфлікти та виконайте \"git commit\")"
+
+msgid "  (use \"git merge --abort\" to abort the merge)"
+msgstr ""
+"  (скористайтесь командою \"git merge --abort\", щоб перервати злиття)."
+
+msgid "All conflicts fixed but you are still merging."
+msgstr "Усі конфлікти виправлено, але ви все ще продовжуєте злиття."
+
+msgid "  (use \"git commit\" to conclude merge)"
+msgstr "  (скористайтесь \"git commit\", щоб завершити злиття)"
+
+msgid "You are in the middle of an am session."
+msgstr "Ви всередині am сеансу."
+
+msgid "The current patch is empty."
+msgstr "Поточна латка порожня."
+
+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\", щоб пропустити цю латку)"
+
+msgid ""
+"  (use \"git am --allow-empty\" to record this patch as an empty commit)"
+msgstr ""
+"  (скористайтесь \"git am --allow-empty\", щоб записати цю латку як порожній "
+"коміт)"
+
+msgid "  (use \"git am --abort\" to restore the original branch)"
+msgstr "  (скористайтесь \"git am --abort\", щоб відновити початкову гілку)"
+
+msgid "git-rebase-todo is missing."
+msgstr "git-rebase-todo відсутній."
+
+msgid "No commands done."
+msgstr "Не виконано жодної команди."
+
+#, c-format
+msgid "Last command done (%<PRIuMAX> command done):"
+msgid_plural "Last commands done (%<PRIuMAX> commands done):"
+msgstr[0] "Останню команду виконано (%<PRIuMAX> команду виконано):"
+msgstr[1] "Останні команди виконано (%<PRIuMAX> команди виконано):"
+msgstr[2] "Останніх команд виконано (%<PRIuMAX> команд виконано):"
+
+#, c-format
+msgid "  (see more in file %s)"
+msgstr "  (дивіться більше у файлі %s)"
+
+msgid "No commands remaining."
+msgstr "Не залишилось команд."
+
+#, c-format
+msgid "Next command to do (%<PRIuMAX> remaining command):"
+msgid_plural "Next commands to do (%<PRIuMAX> remaining commands):"
+msgstr[0] "Наступна команда для виконання (залишилась %<PRIuMAX> команда):"
+msgstr[1] "Наступні команди для виконання (залишилось %<PRIuMAX> команди):"
+msgstr[2] "Наступні команди для виконання (залишилось %<PRIuMAX> команд):"
+
+msgid "  (use \"git rebase --edit-todo\" to view and edit)"
+msgstr ""
+"  (скористайтесь \"git rebase --edit-todo\", щоб переглянути та "
+"відредагувати)"
+
+#, c-format
+msgid "You are currently rebasing branch '%s' on '%s'."
+msgstr "Наразі ви перебазовуєте гілку \"%s\" на \"%s\"."
+
+msgid "You are currently rebasing."
+msgstr "Наразі йде перебазування."
+
+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\", щоб пропустити цю латку)"
+
+msgid "  (use \"git rebase --abort\" to check out the original branch)"
+msgstr ""
+"  (скористайтесь \"git rebase --abort\", щоб перейти до початкової гілки)"
+
+msgid "  (all conflicts fixed: run \"git rebase --continue\")"
+msgstr "  (усі конфлікти виправлено: виконайте \"git rebase --continue\")"
+
+#, c-format
+msgid ""
+"You are currently splitting a commit while rebasing branch '%s' on '%s'."
+msgstr ""
+"Наразі виконується розщеплення коміту під час перебазування гілки \"%s\" на "
+"\"%s\"."
+
+msgid "You are currently splitting a commit during a rebase."
+msgstr "Ви розщеплюєте коміт під час перебазування."
+
+msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
+msgstr ""
+"  (Після очищення робочої директорії виконайте \"git rebase --continue\")"
+
+#, c-format
+msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
+msgstr "Наразі ви редагуєте коміт при перебазуванні гілки \"%s\" на \"%s\"."
+
+msgid "You are currently editing a commit during a rebase."
+msgstr "Наразі ви редагуєте коміт при перебазуванні."
+
+msgid "  (use \"git commit --amend\" to amend the current commit)"
+msgstr ""
+"  (скористайтесь \"git commit --amend\", щоб внести зміни до поточного "
+"коміту)"
+
+msgid ""
+"  (use \"git rebase --continue\" once you are satisfied with your changes)"
+msgstr ""
+"  (скористайтесь командою \"git rebase --continue\", коли ви будете "
+"задоволені своїми змінами)"
+
+msgid "Cherry-pick currently in progress."
+msgstr "Наразі триває висмикування."
+
+#, c-format
+msgid "You are currently cherry-picking commit %s."
+msgstr "Наразі ви висмикуєте коміт %s."
+
+msgid "  (fix conflicts and run \"git cherry-pick --continue\")"
+msgstr "  (виправте конфлікти і виконайте \"git cherry-pick --continue\")"
+
+msgid "  (run \"git cherry-pick --continue\" to continue)"
+msgstr "  (виконайте \"git cherry-pick --continue\", щоб продовжити)"
+
+msgid "  (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr "  (усі конфлікти виправлено: виконайте \"git cherry-pick --continue\")"
+
+msgid "  (use \"git cherry-pick --skip\" to skip this patch)"
+msgstr ""
+"  (скористайтесь командою \"git cherry-pick --skip\", щоб пропустити цю "
+"латку)"
+
+msgid "  (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr ""
+" (скористайтесь командою \"git cherry-pick --abort\", щоб скасувати операцію "
+"висмикування)"
+
+msgid "Revert currently in progress."
+msgstr "Наразі триває вивертання."
+
+#, c-format
+msgid "You are currently reverting commit %s."
+msgstr "Наразі ви вивертаєте коміт %s."
+
+msgid "  (fix conflicts and run \"git revert --continue\")"
+msgstr "  (виправте конфлікти і виконайте \"git revert --continue\")"
+
+msgid "  (run \"git revert --continue\" to continue)"
+msgstr "  (виконайте \"git revert --continue\", щоб продовжити)"
+
+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\", щоб пропустити цю латку)"
+
+msgid "  (use \"git revert --abort\" to cancel the revert operation)"
+msgstr ""
+"  (скористайтесь \"git revert --abort\", щоб скасувати операцію повернення)"
+
+#, c-format
+msgid "You are currently bisecting, started from branch '%s'."
+msgstr "Наразі ви робите бісекцію, починаючи з гілки '%s'."
+
+msgid "You are currently bisecting."
+msgstr "Наразі ви робите бісекцію."
+
+msgid "  (use \"git bisect reset\" to get back to the original branch)"
+msgstr ""
+"  (скористайтесь \"git bisect reset\", щоб повернутись на початкову гілку)"
+
+msgid "You are in a sparse checkout."
+msgstr "Ви перебуваєте в розрідженому переході на гілку."
+
+#, c-format
+msgid "You are in a sparse checkout with %d%% of tracked files present."
+msgstr ""
+"Ви перебуваєте в розрідженому переході на гілку з %d%% наявних відстежуваних "
+"файлів."
+
+msgid "On branch "
+msgstr "На гілці "
+
+msgid "interactive rebase in progress; onto "
+msgstr "триває інтерактивне перебазування на "
+
+msgid "rebase in progress; onto "
+msgstr "триває перебазування на "
+
+msgid "HEAD detached at "
+msgstr "HEAD відʼєднано на "
+
+msgid "HEAD detached from "
+msgstr "HEAD відʼєднано від "
+
+msgid "Not currently on any branch."
+msgstr "Не на гілці."
+
+msgid "Initial commit"
+msgstr "Початковий коміт"
+
+msgid "No commits yet"
+msgstr "Поки що немає комітів"
+
+msgid "Untracked files"
+msgstr "Невідстежувані файли"
+
+msgid "Ignored files"
+msgstr "Ігноровані файли"
+
+#, c-format
+msgid ""
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
+msgstr ""
+"На перерахування невідстежуваних файлів пішло %.2f секунд,\n"
+"але результат було додано у кеш, тому наступні запуски можуть бути швидшими."
+
+#, c-format
+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\" для інформації про те, як це покращити."
+
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr "Невідстежувані файли не показані%s"
+
+msgid " (use -u option to show untracked files)"
+msgstr " (використовуйте опцію -u, щоб показати невідстежувані файли)"
+
+msgid "No changes"
+msgstr "Немає змін"
+
+#, c-format
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr ""
+"не додано жодних змін до коміту (скористайтесь \"git add\" та/або \"git "
+"commit -a\")\n"
+
+#, c-format
+msgid "no changes added to commit\n"
+msgstr "нічого не додано до коміту\n"
+
+#, c-format
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
+msgstr ""
+"нічого не додано до коміту, але є невідстежувані файли (скористайтесь \"git "
+"add\" для відстежування)\n"
+
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "нічого не додано до коміту, але присутні невідстежувані файли\n"
+
+#, c-format
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr ""
+"нічого комітити (створіть/скопіюйте файли та скористайтесь \"git add\" для "
+"відстежування)\n"
+
+#, c-format
+msgid "nothing to commit\n"
+msgstr "нічого комітити\n"
+
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr "нічого комітити (скористайтесь -u щоб показати невідстежувані файли)\n"
+
+#, c-format
+msgid "nothing to commit, working tree clean\n"
+msgstr "нічого комітити, робоче дерево чисте\n"
+
+msgid "No commits yet on "
+msgstr "Поки що немає комітів у "
+
+msgid "HEAD (no branch)"
+msgstr "HEAD (немає гілки)"
+
+msgid "different"
+msgstr "відрізняється"
+
+msgid "behind "
+msgstr "позаду "
+
+msgid "ahead "
+msgstr "попереду "
+
+#. TRANSLATORS: the action is e.g. "pull with rebase"
+
+#, c-format
+msgid "cannot %s: You have unstaged changes."
+msgstr "неможливо %s: У вас є неіндексовані зміни."
+
+msgid "additionally, your index contains uncommitted changes."
+msgstr "крім того, ваш індекс містить незакомічені зміни."
+
+#, c-format
+msgid "cannot %s: Your index contains uncommitted changes."
+msgstr "неможливо виконати %s: Ваш індекс містить незакомічені зміни."
+
+msgid ""
+"Error: Your local changes to the following files would be overwritten by "
+"merge"
+msgstr ""
+"Помилка: Ваші локальні зміни в наступних файлах були б перезаписані під час "
+"злиття"
+
+msgid "Automated merge did not work."
+msgstr "Автоматичне злиття не спрацювало."
+
+msgid "Should not be doing an octopus."
+msgstr "Не слід робити octopus злиття."
+
+#, sh-format
+msgid "Unable to find common commit with $pretty_name"
+msgstr "Не вдалося знайти спільний коміт з $pretty_name"
+
+#, sh-format
+msgid "Already up to date with $pretty_name"
+msgstr "Вже в актуальному стані з $pretty_name"
+
+#, sh-format
+msgid "Fast-forwarding to: $pretty_name"
+msgstr "Перемотування вперед до: $pretty_name"
+
+#, sh-format
+msgid "Trying simple merge with $pretty_name"
+msgstr "Спроба простого злиття з $pretty_name"
+
+msgid "Simple merge did not work, trying automatic merge."
+msgstr "Просте злиття не спрацювало, спроба автоматичного злиття."
+
+#, sh-format
+msgid "usage: $dashless $USAGE"
+msgstr "використання: $dashless $USAGE"
+
+#, sh-format
+msgid "Cannot chdir to $cdup, the toplevel of the working tree"
+msgstr "Неможливо виконати chdir до $cdup, верхнього рівня робочого дерева"
+
+#, sh-format
+msgid "fatal: $program_name cannot be used without a working tree."
+msgstr "збій: $program_name неможливо використовувати без робочого дерева."
+
+msgid "Cannot rewrite branches: You have unstaged changes."
+msgstr "Неможливо переписати гілку: у вас є неіндексовані зміни."
+
+#, sh-format
+msgid "Cannot $action: You have unstaged changes."
+msgstr "Неможливо $action: у вас є неіндексовані зміни."
+
+#, sh-format
+msgid "Cannot $action: Your index contains uncommitted changes."
+msgstr "Неможливо $action: ваш індекс містить незакомічені зміни."
+
+msgid "Additionally, your index contains uncommitted changes."
+msgstr "Крім того, ваш індекс містить незакомічені зміни."
+
+msgid "You need to run this command from the toplevel of the working tree."
+msgstr "Цю команду потрібно запускати з верхнього рівня робочого дерева."
+
+msgid "Unable to determine absolute path of git directory"
+msgstr "Не вдалося визначити абсолютний шлях git директорії"
+
+msgid "local zone differs from GMT by a non-minute interval\n"
+msgstr "місцева зона відрізняється від GMT на нехвилинний інтервал\n"
+
+msgid "local time offset greater than or equal to 24 hours\n"
+msgstr "зміщення місцевого часу більше або дорівнює 24 годинам\n"
+
+#, perl-format
+msgid "fatal: command '%s' died with exit code %d"
+msgstr "збій: команда \"%s\" завершилася невдало з кодом виходу %d"
+
+msgid "the editor exited uncleanly, aborting everything"
+msgstr "редактор вийшов неналежним чином, перервано всі процеси"
+
+#, perl-format
+msgid ""
+"'%s' contains an intermediate version of the email you were composing.\n"
+msgstr "\"%s\" містить проміжну версію листа, який ви створювали.\n"
+
+#, perl-format
+msgid "'%s.final' contains the composed email.\n"
+msgstr "\"%s.final\" містить створений лист.\n"
+
+msgid "--dump-aliases incompatible with other options\n"
+msgstr "--dump-aliases несумісна з іншими опціями\n"
+
+msgid ""
+"fatal: found configuration options for 'sendmail'\n"
+"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
+"Set sendemail.forbidSendmailVariables to false to disable this check.\n"
+msgstr ""
+"збій: знайдено опції конфігурації для \"sendmail\"\n"
+"git-send-email налаштовано з параметрами sendemail.* options - зверніть "
+"увагу на \"e\".\n"
+"Встановіть sendemail.forbidSendmailVariables у false, щоб вимкнути цю "
+"перевірку.\n"
+
+msgid "Cannot run git format-patch from outside a repository\n"
+msgstr "Неможливо запустити git format-patch поза сховищем\n"
+
+msgid ""
+"`batch-size` and `relogin` must be specified together (via command-line or "
+"configuration option)\n"
+msgstr ""
+"\"batch-size\" і \"relogin\" повинні бути вказані разом (через командний "
+"рядок або опції конфігурації)\n"
+
+#, perl-format
+msgid "Unknown --suppress-cc field: '%s'\n"
+msgstr "Невідоме --suppress-cc поле: \"%s\"\n"
+
+#, perl-format
+msgid "Unknown --confirm setting: '%s'\n"
+msgstr "Невідомий --confirm параметр: \"%s\"\n"
+
+#, perl-format
+msgid "warning: sendmail alias with quotes is not supported: %s\n"
+msgstr "попередження: sendmail псевдонім у лапках не підтримується: %s\n"
+
+#, perl-format
+msgid "warning: `:include:` not supported: %s\n"
+msgstr "попередження: \":include:\" не підтримується: %s\n"
+
+#, perl-format
+msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
+msgstr ""
+"попередження: \"/file\" або \"|pipe\" перенаправлення не підтримуються: %s\n"
+
+#, perl-format
+msgid "warning: sendmail line is not recognized: %s\n"
+msgstr "попередження: рядок sendmail не розпізнано: %s\n"
+
+#, perl-format
+msgid ""
+"File '%s' exists but it could also be the range of commits\n"
+"to produce patches for.  Please disambiguate by...\n"
+"\n"
+"    * Saying \"./%s\" if you mean a file; or\n"
+"    * Giving --format-patch option if you mean a range.\n"
+msgstr ""
+"Файл \"%s\" існує, але це також може бути діапазон комітів\n"
+"для яких створюються латки.  Будь ласка, розтлумачте...\n"
+"\n"
+"    * Вказавши \"./%s\", якщо на увазі мається файл\n"
+"    * Додавши --format-patch, якщо на увазі мається діапазон.\n"
+
+#, perl-format
+msgid "Failed to opendir %s: %s"
+msgstr "Не вдалося виконати opendir %s: %s"
+
+msgid ""
+"\n"
+"No patch files specified!\n"
+"\n"
+msgstr ""
+"\n"
+"Файли латок не вказано!\n"
+"\n"
+
+#, perl-format
+msgid "No subject line in %s?"
+msgstr "Немає рядка теми в %s?"
+
+#, perl-format
+msgid "Failed to open for writing %s: %s"
+msgstr "Не вдалося відкрити для запису %s: %s"
+
+msgid ""
+"Lines beginning in \"GIT:\" will be removed.\n"
+"Consider including an overall diffstat or table of contents\n"
+"for the patch you are writing.\n"
+"\n"
+"Clear the body content if you don't wish to send a summary.\n"
+msgstr ""
+"Рядки, що починаються з \"GIT:\", будуть вилучені.\n"
+"Розгляньте можливість включення загального diffstat або змісту\n"
+"для латки, яку ви пишете.\n"
+"\n"
+"Очистіть вміст тіла, якщо ви не бажаєте надсилати підсумок.\n"
+
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "Не вдалося відкрити %s: %s"
+
+#, perl-format
+msgid "Failed to open %s.final: %s"
+msgstr "Не вдалося відкрити %s.final: %s"
+
+msgid "Summary email is empty, skipping it\n"
+msgstr "Підсумковий лист порожній, пропущено\n"
+
+#. TRANSLATORS: please keep [y/N] as is.
+
+#, perl-format
+msgid "Are you sure you want to use <%s> [y/N]? "
+msgstr "Ви впевнені, що хочете використати <%s> [y/N]? "
+
+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]? "
+
+#, perl-format
+msgid ""
+"Refusing to send because the patch\n"
+"\t%s\n"
+"has the template subject '*** SUBJECT HERE ***'. Pass --force if you really "
+"want to send.\n"
+msgstr ""
+"Відмовлено в надсиланні, тому що латка\n"
+"\t%s\n"
+"має шаблонну тему \"*** SUBJECT HERE ***\". Додайте --force, якщо ви дійсно "
+"хочете відправити.\n"
+
+msgid "To whom should the emails be sent (if anyone)?"
+msgstr "Кому слід надсилати електронні листи (якщо комусь)?"
+
+#, perl-format
+msgid "fatal: alias '%s' expands to itself\n"
+msgstr "збій: псевдонім \"%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"
+msgstr "помилка: не вдалося витягти дійсну адресу з: %s\n"
+
+#. TRANSLATORS: Make sure to include [q] [d] [e] in your
+#. translation. The program will only accept English input
+#. at this point.
+
+msgid "What to do with this address? ([q]uit|[d]rop|[e]dit): "
+msgstr "Що робити з цією адресою? ([q]uit|[d]rop|[e]dit): "
+
+#, perl-format
+msgid "CA path \"%s\" does not exist"
+msgstr "Шлях до ЦВС \"%s\" не існує"
+
+msgid ""
+"    The Cc list above has been expanded by additional\n"
+"    addresses found in the patch commit message. By default\n"
+"    send-email prompts before sending whenever this occurs.\n"
+"    This behavior is controlled by the sendemail.confirm\n"
+"    configuration setting.\n"
+"\n"
+"    For additional information, run 'git send-email --help'.\n"
+"    To retain the current behavior, but squelch this message,\n"
+"    run 'git config --global sendemail.confirm auto'.\n"
+"\n"
+msgstr ""
+"    Наведений вище список копій було розширено додатковими\n"
+"    адресами, знайденими у дописі до коміту латки. Зазвичай\n"
+"    send-email запитує перед надсиланням, коли це трапляється.\n"
+"    Цю поведінку можна контролювати за допомогою параметра sendemail."
+"confirm\n"
+"    налаштування конфігурації.\n"
+"\n"
+"    Для отримання додаткової інформації виконайте команду \"git send-email --"
+"help\".\n"
+"Для утримання поточної поведінки, але без цього повідомлення,\n"
+"    виконайте \"git config --global sendemail.confirm auto\".\n"
+
+#. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
+#. translation. The program will only accept English input
+#. at this point.
+
+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 "Відповідь на запитання \"Надіслати цей лист?\" є обовʼязковою"
+
+msgid "The required SMTP server is not properly defined."
+msgstr "Потрібний SMTP-сервер не визначено належним чином."
+
+#, perl-format
+msgid "Server does not support STARTTLS! %s"
+msgstr "Сервер не підтримує STARTTLS! %s"
+
+#, perl-format
+msgid "STARTTLS failed! %s"
+msgstr "STARTTLS завершився невдало! %s"
+
+msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
+msgstr ""
+"Не вдалося правильно ініціалізувати SMTP. Перевірте конфігурацію і "
+"скористайтесь --smtp-debug."
+
+#, perl-format
+msgid "Failed to send %s\n"
+msgstr "Не вдалося надіслати %s\n"
+
+#, perl-format
+msgid "Dry-Sent %s\n"
+msgstr "Пробно відправлено %s\n"
+
+#, perl-format
+msgid "Sent %s\n"
+msgstr "Відправлено %s\n"
+
+msgid "Dry-OK. Log says:\n"
+msgstr "Пробно OK. Журнал каже:\n"
+
+msgid "OK. Log says:\n"
+msgstr "ОК. Журнал каже:\n"
+
+msgid "Result: "
+msgstr "Результат: "
+
+msgid "Result: OK\n"
+msgstr "Результат: OK\n"
+
+#, perl-format
+msgid "can't open file %s"
+msgstr "неможливо відкрити файл %s"
+
+#, perl-format
+msgid "(mbox) Adding cc: %s from line '%s'\n"
+msgstr "(mbox) Додавання cc: %s з рядка \"%s\"\n"
+
+#, perl-format
+msgid "(mbox) Adding to: %s from line '%s'\n"
+msgstr "(mbox) Додавання до: %s з рядка \"%s\"\n"
+
+#, perl-format
+msgid "(non-mbox) Adding cc: %s from line '%s'\n"
+msgstr "(non-mbox) Додавання cc: %s з рядка \"%s\"\n"
+
+#, perl-format
+msgid "(body) Adding cc: %s from line '%s'\n"
+msgstr "(тіло) Додавання cc: %s з рядка \"%s\"\n"
+
+#, perl-format
+msgid "(%s) Could not execute '%s'"
+msgstr "(%s) Не вдалося виконати \"%s\""
+
+#, perl-format
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Невірно сформований вивід з \"%s\""
+
+#, 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 "неможливо надіслати повідомлення як 7bit"
+
+msgid "invalid transfer encoding"
+msgstr "неприпустиме кодування передачі"
+
+#, perl-format
+msgid ""
+"fatal: %s: rejected by %s hook\n"
+"%s\n"
+"warning: no patches were sent\n"
+msgstr ""
+"збій: %s: відхилено %s хуком\n"
+"%s\n"
+"попередження: не було надіслано жодних латок\n"
+
+#, perl-format
+msgid "unable to open %s: %s\n"
+msgstr "не вдалося відкрити %s: %s\n"
+
+#, perl-format
+msgid ""
+"fatal: %s:%d is longer than 998 characters\n"
+"warning: no patches were sent\n"
+msgstr ""
+"збій: %s:%d довше ніж 998 символів\n"
+"попередження: не було надіслано жодних латок\n"
+
+#, perl-format
+msgid "Skipping %s with backup suffix '%s'.\n"
+msgstr "Пропуск %s з суфіксом резервної копії \"%s\".\n"
+
+#. TRANSLATORS: please keep "[y|N]" as is.
+
+#, perl-format
+msgid "Do you really want to send %s? [y|N]: "
+msgstr "Ви дійсно хочете відправити %s? [y|N]: "
index 2b88f9b78146c7097d193af0092db9d33443916d..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
 #
 #   3-way merge                      |  三方合并
 #   abbreviate                       |  简写(的 SHA-1 值)
 #   alternate object database        |  备用对象库
+#   attribute source                 |  属性来源
 #   amend                            |  修补
 #   ancestor                         |  祖先,祖先提交
 #   annotated tag                    |  附注标签
 #   bare repository                  |  纯仓库
 #   bisect                           |  二分查找
+#   bitmap                           |  位图
 #   blob object                      |  数据对象
 #   bloom filter                     |  布隆过滤器
 #   branch                           |  分支
@@ -74,6 +77,7 @@
 #   index entry                      |  索引条目
 #   loose object                     |  松散对象
 #   loose refs                       |  松散引用
+#   magic                            |  神奇前缀(路径规格支持的一种前缀表达式)
 #   master                           |  master(默认分支名)
 #   merge                            |  合并
 #   object                           |  对象
@@ -83,6 +87,7 @@
 #   object type                      |  对象类型
 #   octopus                          |  章鱼式合并(两分支以上的合并)
 #   origin                           |  origin(默认的远程名称)
+#   orphan                           |  孤立(一般指孤立分支,即没有任何提交的分支)
 #   pack                             |  包
 #   pack index                       |  包索引
 #   packfile                         |  包文件
 #   rebase                           |  变基
 #   ref                              |  引用
 #   reflog                           |  引用日志
+#   refmap                           |  引用映射
 #   refspec                          |  引用规格
 #   remote                           |  远程,远程仓库
 #   remote-tracking branch           |  远程跟踪分支
@@ -145,10 +151,10 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-03-07 23:37+0000\n"
-"PO-Revision-Date: 2023-03-07 23:40+0000\n"
-"Last-Translator: Fangyi Zhou <me@fangyi.io>\n"
-"Language-Team: GitHub <https://github.com/fangyi-zhou/git-po/>\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"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -888,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 ""
@@ -916,6 +921,24 @@ msgstr "请在合并前先提交您的修改。"
 msgid "Exiting because of unfinished merge."
 msgstr "因为存在未完成的合并而退出。"
 
+#: advice.c
+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 ""
+"无法在偏离的分支上进行快进操作,您需要:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"或者:\n"
+"\n"
+"\tgit rebase\n"
+
 #: advice.c
 msgid "Not possible to fast-forward, aborting."
 msgstr "无法快进,终止。"
@@ -1039,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"
@@ -1444,6 +1475,11 @@ msgstr "截短 .rej 文件名为 %.*s.rej"
 msgid "cannot open %s"
 msgstr "不能打开 %s"
 
+#: apply.c rerere.c
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "不能删除 '%s'"
+
 #: apply.c
 #, c-format
 msgid "Hunk #%d applied cleanly."
@@ -1681,6 +1717,11 @@ msgstr "git archive --remote <仓库> [--exec <命令>] --list"
 msgid "cannot read '%s'"
 msgstr "不能读取 '%s'"
 
+#: archive.c
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "路径规格 '%s' 匹配了当前目录外的文件'"
+
 #: archive.c builtin/add.c builtin/rm.c
 #, c-format
 msgid "pathspec '%s' did not match any files"
@@ -1701,10 +1742,6 @@ msgstr "不是一个有效的对象名:%s"
 msgid "not a tree object: %s"
 msgstr "不是一个树对象:%s"
 
-#: archive.c
-msgid "current working directory is untracked"
-msgstr "当前工作目录未被跟踪"
-
 #: archive.c
 #, c-format
 msgid "File not found: %s"
@@ -1873,6 +1910,10 @@ msgstr "忽略过大的 gitattributes 文件 '%s'"
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "忽略过大的 gitattributes 数据对象 '%s'"
 
+#: attr.c
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "错误的 --attr-source 或 GIT_ATTR_SOURCE"
+
 #: bisect.c
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
@@ -1996,17 +2037,13 @@ msgstr[1] "二分查找中:在此之后,还剩 %d 个版本待测试 %s\n"
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents 和 --reverse 不能混用。"
 
-#: blame.c
-msgid "cannot use --contents with final commit object name"
-msgstr "不能将 --contents 和最终的提交对象名共用"
-
 #: blame.c
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c ref-filter.c
-#: remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c remote.c
+#: sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "版本遍历初始化失败"
 
@@ -2130,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
@@ -2200,11 +2237,6 @@ msgstr "子模组 '%s':不能创建分支 '%s'"
 msgid "'%s' is already checked out at '%s'"
 msgstr "'%s' 已经检出到 '%s'"
 
-#: branch.c
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "工作区 %s 的 HEAD 指向没有被更新"
-
 #: builtin/add.c
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<选项>] [--] <路径规格>..."
@@ -2214,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 "刷新索引之后尚未被暂存的变更:"
@@ -2472,7 +2490,7 @@ msgstr "fseek 失败"
 msgid "could not open '%s' for reading"
 msgstr "无法打开 '%s' 进行读取"
 
-#: builtin/am.c builtin/rebase.c sequencer.c strbuf.c wrapper.c
+#: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "无法打开 '%s' 进行写入"
@@ -2754,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 "丢弃裁切线前的所有内容"
@@ -3494,6 +3508,15 @@ msgstr "无法删除检出于 '%2$s' 的分支 '%1$s'。"
 msgid "remote-tracking branch '%s' not found."
 msgstr "未能找到远程跟踪分支 '%s'。"
 
+#: builtin/branch.c
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"分支 '%s' 未找到。\n"
+"是否忘记指定 --remote 选项?"
+
 #: builtin/branch.c
 #, c-format
 msgid "branch '%s' not found."
@@ -3532,6 +3555,11 @@ msgstr "分支 %s 正被变基到 %s"
 msgid "Branch %s is being bisected at %s"
 msgstr "分支 %s 正被二分查找于 %s"
 
+#: builtin/branch.c
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "工作区 %s 的 HEAD 指向没有被更新"
+
 #: builtin/branch.c
 #, c-format
 msgid "Invalid branch name: '%s'"
@@ -3661,6 +3689,10 @@ msgstr "移动/重命名一个分支,以及它的引用日志"
 msgid "move/rename a branch, even if target exists"
 msgstr "移动/重命名一个分支,即使目标已存在"
 
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
+msgid "do not output a newline after empty formatted refs"
+msgstr "在格式化引用结果为空之后,不输出换行符"
+
 #: builtin/branch.c
 msgid "copy a branch and its reflog"
 msgstr "拷贝一个分支和它的引用日志"
@@ -3928,12 +3960,10 @@ msgstr "在 '%s' 创建了新报告。\n"
 
 #: builtin/bundle.c
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<版本>] <文件> <git-rev-list-参数>"
 
 #: builtin/bundle.c
@@ -3960,13 +3990,13 @@ msgstr "不显示进度表"
 msgid "show progress meter"
 msgstr "显示进度表"
 
-#: builtin/bundle.c builtin/pack-objects.c
-msgid "show progress meter during object writing phase"
-msgstr "在对象写入阶段显示进度表"
+#: builtin/bundle.c
+msgid "historical; same as --progress"
+msgstr "老的参数;等同于 --progress"
 
-#: builtin/bundle.c builtin/pack-objects.c
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "当进度表显示时类似于 --all-progress"
+#: builtin/bundle.c
+msgid "historical; does nothing"
+msgstr "老的参数;无作用"
 
 #: builtin/bundle.c
 msgid "specify bundle format version"
@@ -4042,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 ""
@@ -4105,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 "从标准输入读取命令"
@@ -5001,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 "模式"
 
@@ -5171,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 "对子模组使用部分克隆过滤器"
@@ -5214,6 +5241,11 @@ msgstr "无法对 '%s' 调用 stat"
 msgid "%s exists and is not a directory"
 msgstr "%s 存在且不是一个目录"
 
+#: builtin/clone.c
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "'%s' 为符号链接,拒绝用 --local 克隆"
+
 #: builtin/clone.c
 #, c-format
 msgid "failed to start iterator over '%s'"
@@ -5708,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 树对象"
@@ -5783,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
@@ -6001,7 +6037,7 @@ msgstr "计算完整的领先/落后值"
 msgid "version"
 msgstr "版本"
 
-#: builtin/commit.c builtin/push.c builtin/worktree.c
+#: builtin/commit.c builtin/fetch.c builtin/push.c builtin/worktree.c
 msgid "machine-readable output"
 msgstr "机器可读的输出"
 
@@ -7076,145 +7112,15 @@ msgstr "git fetch --all [<选项>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel 不能为负数"
 
-#: builtin/fetch.c builtin/pull.c
-msgid "fetch from all remotes"
-msgstr "从所有的远程抓取"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "set upstream for git pull/fetch"
-msgstr "为 git pull/fetch 设置上游"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "追加到 .git/FETCH_HEAD 而不是覆盖它"
-
-#: builtin/fetch.c
-msgid "use atomic transaction to update references"
-msgstr "使用原子事务更新引用"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "path to upload pack on remote end"
-msgstr "上传包到远程的路径"
-
-#: builtin/fetch.c
-msgid "force overwrite of local reference"
-msgstr "强制覆盖本地引用"
-
-#: builtin/fetch.c
-msgid "fetch from multiple remotes"
-msgstr "从多个远程抓取"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "fetch all tags and associated objects"
-msgstr "抓取所有的标签和关联对象"
-
-#: builtin/fetch.c
-msgid "do not fetch all tags (--no-tags)"
-msgstr "不抓取任何标签(--no-tags)"
-
-#: builtin/fetch.c
-msgid "number of submodules fetched in parallel"
-msgstr "子模组获取的并发数"
-
-#: builtin/fetch.c
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr "修改引用规格以将所有引用放入 refs/prefetch/"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "prune remote-tracking branches no longer on remote"
-msgstr "清除远程已经不存在的分支的跟踪分支"
-
-#: builtin/fetch.c
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr "清除远程不存在的本地标签,并且替换变更标签"
-
-#  译者:可选值,不能翻译
-#: builtin/fetch.c builtin/pull.c
-msgid "on-demand"
-msgstr "on-demand"
-
-#: builtin/fetch.c
-msgid "control recursive fetching of submodules"
-msgstr "控制子模组的递归抓取"
-
-#: builtin/fetch.c
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "将获取到的引用写入 FETCH_HEAD 文件"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "keep downloaded pack"
-msgstr "保持下载包"
-
-#: builtin/fetch.c
-msgid "allow updating of HEAD ref"
-msgstr "允许更新 HEAD 引用"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow clone"
-msgstr "深化浅克隆的历史"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow repository based on time"
-msgstr "基于时间来深化浅克隆的历史"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "convert to a complete repository"
-msgstr "转换为一个完整的仓库"
-
-#: builtin/fetch.c
-msgid "re-fetch without negotiating common commits"
-msgstr "不协商共有提交重新获取"
-
-#: builtin/fetch.c
-msgid "prepend this to submodule path output"
-msgstr "在子模组路径输出的前面加上此目录"
-
-#: builtin/fetch.c
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr "递归获取子模组的缺省值(比配置文件优先级低)"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "accept refs that update .git/shallow"
-msgstr "接受更新 .git/shallow 的引用"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "refmap"
-msgstr "引用映射"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "specify fetch refmap"
-msgstr "指定获取操作的引用映射"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "report that we have only objects reachable from this object"
-msgstr "报告我们只拥有从该对象开始可达的对象"
-
-#: builtin/fetch.c
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr "不获取包文件;而是打印协商的祖先提交"
-
-#: builtin/fetch.c
-msgid "run 'maintenance --auto' after fetching"
-msgstr "获取后执行 'maintenance --auto'"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "check for forced-updates on all updated branches"
-msgstr "在所有更新分支上检查强制更新"
-
-#: builtin/fetch.c
-msgid "write the commit-graph after fetching"
-msgstr "抓取后写提交图"
-
-#: builtin/fetch.c
-msgid "accept refspecs from stdin"
-msgstr "从标准输入获取引用规格"
-
 #: builtin/fetch.c
 msgid "couldn't find remote ref HEAD"
 msgstr "无法发现远程 HEAD 引用"
 
+#: builtin/fetch.c
+#, c-format
+msgid "From %.*s\n"
+msgstr "来自 %.*s\n"
+
 #: builtin/fetch.c
 #, c-format
 msgid "object %s not found"
@@ -7300,11 +7206,6 @@ msgstr "%s 未发送所有必需的对象\n"
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr "拒绝 %s 因为浅克隆的根不允许被更新"
 
-#: builtin/fetch.c
-#, c-format
-msgid "From %.*s\n"
-msgstr "来自 %.*s\n"
-
 #: builtin/fetch.c
 #, c-format
 msgid ""
@@ -7370,50 +7271,185 @@ msgid ""
 "any branch."
 msgstr "无法在不指向任何分支时将 HEAD 的上游从 '%s' 设置为 '%s'。"
 
-#: builtin/fetch.c
-msgid "not setting upstream for a remote remote-tracking branch"
-msgstr "没有为一个远程跟踪分支设置上游"
+#: builtin/fetch.c
+msgid "not setting upstream for a remote remote-tracking branch"
+msgstr "没有为一个远程跟踪分支设置上游"
+
+#: builtin/fetch.c
+msgid "not setting upstream for a remote tag"
+msgstr "没有为一个远程标签设置上游"
+
+#: builtin/fetch.c
+msgid "unknown branch type"
+msgstr "未知的分支类型"
+
+#: builtin/fetch.c
+msgid ""
+"no source branch found;\n"
+"you need to specify exactly one branch with the --set-upstream option"
+msgstr ""
+"未发现源分支;\n"
+"您需要使用 --set-upstream 选项指定一个分支"
+
+#: builtin/fetch.c
+#, c-format
+msgid "Fetching %s\n"
+msgstr "正在获取 %s\n"
+
+#: builtin/fetch.c
+#, c-format
+msgid "could not fetch %s"
+msgstr "不能获取 %s"
+
+#: builtin/fetch.c
+#, c-format
+msgid "could not fetch '%s' (exit code: %d)\n"
+msgstr "无法获取 '%s'(退出码:%d)\n"
+
+#: builtin/fetch.c
+msgid ""
+"no remote repository specified; please specify either a URL or a\n"
+"remote name from which new revisions should be fetched"
+msgstr "未指定远程仓库;请指定一个用于获取新版本的 URL 或远程仓库名"
+
+#: builtin/fetch.c
+msgid "you need to specify a tag name"
+msgstr "您需要指定一个标签名称"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "fetch from all remotes"
+msgstr "从所有远程抓取"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "set upstream for git pull/fetch"
+msgstr "为 git pull/fetch 设置上游"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "追加到 .git/FETCH_HEAD 而不是覆盖它"
+
+#: builtin/fetch.c
+msgid "use atomic transaction to update references"
+msgstr "使用原子事务更新引用"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "path to upload pack on remote end"
+msgstr "上传包到远程的路径"
+
+#: builtin/fetch.c
+msgid "force overwrite of local reference"
+msgstr "强制覆盖本地引用"
+
+#: builtin/fetch.c
+msgid "fetch from multiple remotes"
+msgstr "从多个远程抓取"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "fetch all tags and associated objects"
+msgstr "抓取所有的标签和关联对象"
+
+#: builtin/fetch.c
+msgid "do not fetch all tags (--no-tags)"
+msgstr "不抓取任何标签(--no-tags)"
+
+#: builtin/fetch.c
+msgid "number of submodules fetched in parallel"
+msgstr "获取子模组的并发数"
+
+#: builtin/fetch.c
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr "修改引用规格以将所有引用放入 refs/prefetch/"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "清除远程已经不存在的分支的跟踪分支"
+
+#: builtin/fetch.c
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr "清除远程不存在的本地标签,并且替换变更标签"
+
+#  译者:可选值,不能翻译
+#: builtin/fetch.c builtin/pull.c
+msgid "on-demand"
+msgstr "on-demand"
+
+#: builtin/fetch.c
+msgid "control recursive fetching of submodules"
+msgstr "控制子模组的递归抓取"
+
+#: builtin/fetch.c
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "将获取到的引用写入 FETCH_HEAD 文件"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "keep downloaded pack"
+msgstr "保持已下载的包"
+
+#: builtin/fetch.c
+msgid "allow updating of HEAD ref"
+msgstr "允许更新 HEAD 引用"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow clone"
+msgstr "深化浅克隆的历史"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow repository based on time"
+msgstr "基于时间来深化浅克隆的历史"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "convert to a complete repository"
+msgstr "转换为一个完整的仓库"
 
 #: builtin/fetch.c
-msgid "not setting upstream for a remote tag"
-msgstr "没有为一个远程标签设置上游"
+msgid "re-fetch without negotiating common commits"
+msgstr "重新获取而不协商共同提交"
 
 #: builtin/fetch.c
-msgid "unknown branch type"
-msgstr "未知的分支类型"
+msgid "prepend this to submodule path output"
+msgstr "在子模组路径输出的前面加上此目录"
 
 #: builtin/fetch.c
 msgid ""
-"no source branch found;\n"
-"you need to specify exactly one branch with the --set-upstream option"
-msgstr ""
-"未发现源分支;\n"
-"您需要使用 --set-upstream 选项指定一个分支"
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr "递归获取子模组的缺省值(比配置文件优先级低)"
 
-#: builtin/fetch.c
-#, c-format
-msgid "Fetching %s\n"
-msgstr "正在获取 %s\n"
+#: builtin/fetch.c builtin/pull.c
+msgid "accept refs that update .git/shallow"
+msgstr "接受更新 .git/shallow 的引用"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "refmap"
+msgstr "引用映射"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "specify fetch refmap"
+msgstr "指定获取操作的引用映射"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "report that we have only objects reachable from this object"
+msgstr "报告我们只拥有从该对象开始可达的对象"
 
 #: builtin/fetch.c
-#, c-format
-msgid "could not fetch %s"
-msgstr "不能获取 %s"
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr "不获取包文件;而是打印协商的祖先提交"
 
 #: builtin/fetch.c
-#, c-format
-msgid "could not fetch '%s' (exit code: %d)\n"
-msgstr "无法获取 '%s'(退出码:%d)\n"
+msgid "run 'maintenance --auto' after fetching"
+msgstr "获取后执行 'maintenance --auto'"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "check for forced-updates on all updated branches"
+msgstr "在所有更新分支上检查强制更新"
 
 #: builtin/fetch.c
-msgid ""
-"no remote repository specified; please specify either a URL or a\n"
-"remote name from which new revisions should be fetched"
-msgstr "未指定远程仓库;请指定一个用于获取新版本的 URL 或远程仓库名"
+msgid "write the commit-graph after fetching"
+msgstr "抓取后写提交图"
 
 #: builtin/fetch.c
-msgid "you need to specify a tag name"
-msgstr "您需要指定一个标签名称"
+msgid "accept refspecs from stdin"
+msgstr "从标准输入获取引用规格"
 
 #: builtin/fetch.c
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
@@ -7560,6 +7596,14 @@ msgstr "只打印包含该提交的引用"
 msgid "print only refs which don't contain the commit"
 msgstr "只打印不包含该提交的引用"
 
+#: builtin/for-each-ref.c
+msgid "read reference patterns from stdin"
+msgstr "从标准输入读取引用的模式"
+
+#: builtin/for-each-ref.c
+msgid "unknown arguments supplied with --stdin"
+msgstr "为 --stdin 提供了未知的命令参数"
+
 #: builtin/for-each-repo.c
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<配置> [--] <命令参数>"
@@ -7576,6 +7620,11 @@ msgstr "存储着仓库路径列表的配置项键名"
 msgid "missing --config=<config>"
 msgstr "缺少 --config=<配置>"
 
+#: builtin/for-each-repo.c
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "发现错误的配置行 --config=%s"
+
 #: builtin/fsck.c
 msgid "unknown"
 msgstr "未知"
@@ -7761,13 +7810,14 @@ msgid "notice: %s points to an unborn branch (%s)"
 msgstr "注意:%s 指向一个尚未诞生的分支(%s)"
 
 #: builtin/fsck.c
-msgid "Checking cache tree"
-msgstr "正在检查缓存树"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "正在检查缓存树 %s"
 
 #: builtin/fsck.c
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s:cache-tree 无效的 sha1 指针"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s:cache-tree %s 中存在无效的 sha1 指针"
 
 #: builtin/fsck.c
 msgid "non-tree in cache-tree"
@@ -7775,8 +7825,18 @@ msgstr "cache-tree 中非树对象"
 
 #: builtin/fsck.c
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s:resolve-undo 中无效的 sha1 指针"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s:resolve-undo %s 中存在无效的 sha1 指针"
+
+#: builtin/fsck.c
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "无法为包文件 %s 加载反向索引"
+
+#: builtin/fsck.c
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "包文件 '%s' 的反向索引文件无效"
 
 #: builtin/fsck.c
 msgid ""
@@ -7983,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"
@@ -8994,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'"
@@ -9011,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"
@@ -9647,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 '('"
@@ -9832,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 '('"
@@ -10371,7 +10342,7 @@ msgstr "对于 %s 没有来自 %s 的远程跟踪分支"
 msgid "Bad value '%s' in environment '%s'"
 msgstr "环境 '%2$s' 中存在坏的取值 '%1$s'"
 
-#: builtin/merge.c read-cache.c strbuf.c wrapper.c
+#: builtin/merge.c editor.c read-cache.c wrapper.c
 #, c-format
 msgid "could not close '%s'"
 msgstr "不能关闭 '%s'"
@@ -10762,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>"
@@ -10774,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>]"
@@ -10946,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 ""
@@ -11204,7 +11191,7 @@ msgstr "无法写入位图索引"
 msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
 msgstr "写入 %<PRIu32> 个对象而预期 %<PRIu32> 个"
 
-#: builtin/pack-objects.c
+#: builtin/pack-objects.c builtin/repack.c
 msgid "disabling bitmap writing, as some objects are not being packed"
 msgstr "禁用 bitmap 写入,因为一些对象将不会被打包"
 
@@ -11370,6 +11357,14 @@ msgstr "不支持的索引版本 %s"
 msgid "bad index version '%s'"
 msgstr "坏的索引版本 '%s'"
 
+#: builtin/pack-objects.c
+msgid "show progress meter during object writing phase"
+msgstr "在对象写入阶段显示进度表"
+
+#: builtin/pack-objects.c
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "当进度表显示时类似于 --all-progress"
+
 #: builtin/pack-objects.c
 msgid "<version>[,<offset>]"
 msgstr "<版本>[,<偏移>]"
@@ -11611,9 +11606,16 @@ msgstr ""
 "并通过发送邮件到 <git@vger.kernel.org> 让我们知道您仍旧\n"
 "使用它。 谢谢。\n"
 
+#: builtin/pack-redundant.c
+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"
@@ -11623,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]"
@@ -11699,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 "
@@ -11812,9 +11830,9 @@ msgstr "更新尚未诞生的分支,变更添加至索引。"
 msgid "pull with rebase"
 msgstr "变基式拉取"
 
-#: builtin/pull.c
-msgid "please commit or stash them."
-msgstr "请提交或贮藏它们。"
+#: builtin/pull.c builtin/rebase.c
+msgid "Please commit or stash them."
+msgstr "请提交或贮藏修改。"
 
 #: builtin/pull.c
 #, c-format
@@ -11980,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
@@ -12027,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
@@ -12061,9 +12080,9 @@ msgstr "'%s' 的值无效"
 msgid "repository"
 msgstr "仓库"
 
-#: builtin/push.c builtin/send-pack.c
-msgid "push all refs"
-msgstr "æ\8e¨é\80\81æ\89\80æ\9c\89å¼\95ç\94¨"
+#: builtin/push.c
+msgid "push all branches"
+msgstr "æ\8e¨é\80\81æ\89\80æ\9c\89å\88\86æ\94¯"
 
 #: builtin/push.c builtin/send-pack.c
 msgid "mirror all refs"
@@ -12074,8 +12093,8 @@ msgid "delete refs"
 msgstr "删除引用"
 
 #: builtin/push.c
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "推送标签(不能使用 --all or --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr "推送标签(不能使用 --all or --branches or --mirror)"
 
 #: builtin/push.c builtin/send-pack.c
 msgid "force updates"
@@ -12397,6 +12416,11 @@ msgstr ""
 "\n"
 "因此 git 无法对其变基。"
 
+#: builtin/rebase.c
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "未知的变基合并模式:%s"
+
 #: builtin/rebase.c
 #, c-format
 msgid "could not switch to %s"
@@ -12413,6 +12437,16 @@ msgid ""
 "\"ask\"."
 msgstr "无法识别的空类型 '%s';有效值有 \"drop\"、\"keep\" 和 \"ask\"。"
 
+#: builtin/rebase.c
+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 未来\n"
+"的版本中将不再支持。 支持使用无参数 --rebase-merges 的方式进行替\n"
+"代,它们具有相同的作用。"
+
 #: builtin/rebase.c
 #, c-format
 msgid ""
@@ -12675,20 +12709,21 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "开关 `C' 期望一个数字值"
 
-#: builtin/rebase.c
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "未知模式:%s"
-
 #: builtin/rebase.c
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy 需要 --merge 或 --interactive"
 
 #: builtin/rebase.c
 msgid ""
-"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
-msgstr "应用的选项与 rebase.autosquash 不兼容。考虑加上 --no-autosquash"
+msgstr "应用的选项与 rebase.autoSquash 不兼容。考虑加上 --no-autosquash"
+
+#: builtin/rebase.c
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr "应用的选项与 rebase.rebaseMerges 不兼容。考虑加上 --no-rebase-merges"
 
 #: builtin/rebase.c
 msgid ""
@@ -12743,10 +12778,6 @@ msgstr "'%s':只需要一个合并基线"
 msgid "Does not point to a valid commit '%s'"
 msgstr "没有指向一个有效的提交 '%s'"
 
-#: builtin/rebase.c
-msgid "Please commit or stash them."
-msgstr "请提交或贮藏修改。"
-
 #: builtin/rebase.c
 msgid "HEAD is up to date."
 msgstr "HEAD 是最新的。"
@@ -13050,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"
@@ -13549,8 +13578,8 @@ msgid "approxidate"
 msgstr "近似日期"
 
 #: builtin/repack.c
-msgid "with -C, expire objects older than this"
-msgstr "使用 -C,使早于给定时间的对象过期"
+msgid "with --cruft, expire objects older than this"
+msgstr "使用 --cruft,使早于给定时间的对象过期"
 
 #: builtin/repack.c
 msgid "remove redundant packs, and run git-prune-packed"
@@ -14381,6 +14410,10 @@ msgstr ""
 msgid "remote name"
 msgstr "远程名称"
 
+#: builtin/send-pack.c
+msgid "push all refs"
+msgstr "推送所有引用"
+
 #: builtin/send-pack.c
 msgid "use stateless RPC protocol"
 msgstr "使用无状态的 RPC 协议"
@@ -14638,9 +14671,11 @@ msgstr "显示从标准输入中读入的不在本地仓库中的引用"
 
 #: builtin/sparse-checkout.c
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<选项>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check\n"
+"-rules) [<选项>]"
 
 #: builtin/sparse-checkout.c
 msgid "this worktree is not sparse"
@@ -14777,8 +14812,28 @@ msgid "must be in a sparse-checkout to reapply sparsity patterns"
 msgstr "必须在稀疏检出中重应用稀疏模式"
 
 #: builtin/sparse-checkout.c
-msgid "error while refreshing working directory"
-msgstr "刷新工作目录时出错"
+msgid "error while refreshing working directory"
+msgstr "刷新工作目录时出错"
+
+#: builtin/sparse-checkout.c
+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 <文件>]"
+
+#: builtin/sparse-checkout.c
+msgid "terminate input and output files by a NUL character"
+msgstr "输入和输出的文件使用 NUL 字符终结"
+
+#: builtin/sparse-checkout.c
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr "通过 --rules-file 选项传递的模型将被作为锥形(稀疏检出模型)进行解析"
+
+#: builtin/sparse-checkout.c
+msgid "use patterns in <file> instead of the current ones."
+msgstr "从 <文件> 参数中读取模式,而不是从标准输入"
 
 #: builtin/stash.c
 msgid "git stash list [<log-options>]"
@@ -15413,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"
@@ -16325,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]]"
@@ -16358,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"
@@ -16438,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 "检出 <分支>,即使已经被检出到其它工作区"
@@ -16455,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 "生成新的工作区"
@@ -16480,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 添加"
@@ -16760,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 "无法复制归档包描述符"
@@ -17057,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"
@@ -17598,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"
@@ -17705,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 "正在扫描合并提交"
@@ -17740,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"
@@ -17791,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!"
@@ -18313,8 +18475,8 @@ msgid "bad zlib compression level %d"
 msgstr "错误的 zlib 压缩级别 %d"
 
 #: config.c
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar 应该是一个字符"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar 应该是一个 ASCII 编码的字符"
 
 #: config.c
 #, c-format
@@ -18452,6 +18614,11 @@ msgstr "不能设置 '%s' 为 '%s'"
 msgid "invalid section name: %s"
 msgstr "无效的小节名称:%s"
 
+#: config.c
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr "拒绝支持内容过长的行,位于文件 '%s' 中的第 %<PRIuMAX> 行"
+
 #: config.c
 #, c-format
 msgid "missing value for '%s'"
@@ -18942,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 [<选项>] <路径> <路径>"
@@ -19006,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"
@@ -19022,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"
@@ -19262,6 +19442,10 @@ msgstr "输出的每一行附加前缀"
 msgid "do not show any source or destination prefix"
 msgstr "不显示任何源和目标前缀"
 
+#: diff.c
+msgid "use default prefixes a/ and b/"
+msgstr "使用 a/ 和 b/ 作为默认前缀"
+
 #: diff.c
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr "显示指定行数的差异块间的上下文"
@@ -19631,6 +19815,16 @@ msgstr "不能从 '%s' 迁移 git 目录到 '%s'"
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "提示:等待您的编辑器关闭文件...%c"
 
+#: editor.c sequencer.c wrapper.c
+#, c-format
+msgid "could not write to '%s'"
+msgstr "不能写入 '%s'"
+
+#: editor.c
+#, c-format
+msgid "could not edit '%s'"
+msgstr "不能编辑 '%s'"
+
 #: entry.c
 msgid "Filtering content"
 msgstr "过滤内容"
@@ -19997,6 +20191,11 @@ msgstr "应为 -c 提供一个配置字符串\n"
 msgid "no config key given for --config-env\n"
 msgstr "没有为 --config-env 提供配置名称\n"
 
+#: git.c
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "没有为 --attr-source 提供属性来源\n"
+
 #: git.c
 #, c-format
 msgid "unknown option: %s\n"
@@ -21978,6 +22177,11 @@ msgstr "无法在包 '%2$s' 偏移 %3$<PRIuMAX> 中找到 '%1$s'"
 msgid "unable to get disk usage of '%s'"
 msgstr "无法得到 '%s' 的磁盘使用量"
 
+#: pack-bitmap.c
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "位图文件 '%s' 有无效的校验码"
+
 #: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s is too small"
@@ -22028,6 +22232,15 @@ msgstr "反向索引文件 %s 不支持的版本 %<PRIu32>"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "反向索引文件 %s 有不支持的哈希 ID %<PRIu32>"
 
+#: pack-revindex.c
+msgid "invalid checksum"
+msgstr "无效的校验码 %s"
+
+#: pack-revindex.c
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "位于 %<PRIu64> 的无效的反向索引:%<PRIu32> != %<PRIu32>"
+
 #: pack-write.c
 msgid "cannot both write and verify reverse index"
 msgstr "无法同时写入和校验反向索引"
@@ -22452,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)"
@@ -22639,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 --"
@@ -22852,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)"
@@ -22882,6 +23134,11 @@ msgstr "未能识别的 %%(%s) 参数:%s"
 msgid "positive width expected with the %%(align) atom"
 msgstr "元素 %%(align) 需要一个正数的宽度"
 
+#: ref-filter.c
+#, c-format
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "期望的格式:%%(ahead-behind:<提交号>)"
+
 #: ref-filter.c
 #, c-format
 msgid "malformed field name: %.*s"
@@ -22938,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)"
@@ -23015,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"
@@ -23544,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
@@ -23635,11 +23901,6 @@ msgstr "无法更新 '%s' 中的冲突状态"
 msgid "no remembered resolution for '%s'"
 msgstr "没有为 '%s' 记忆的解决方案"
 
-#: rerere.c
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "不能删除 '%s'"
-
 #: rerere.c
 #, c-format
 msgid "Updated preimage for '%s'"
@@ -23690,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 "您的当前分支好像被损坏"
@@ -24052,11 +24318,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "不能锁定 '%s'"
 
-#: sequencer.c strbuf.c wrapper.c
-#, c-format
-msgid "could not write to '%s'"
-msgstr "不能写入 '%s'"
-
 #: sequencer.c
 #, c-format
 msgid "could not write eol to '%s'"
@@ -24494,10 +24755,6 @@ msgstr "尝试 \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgid "could not create sequencer directory '%s'"
 msgstr "不能创建序列目录 '%s'"
 
-#: sequencer.c
-msgid "could not lock HEAD"
-msgstr "不能锁定 HEAD"
-
 #: sequencer.c
 msgid "no cherry-pick or revert in progress"
 msgstr "拣选或还原操作并未进行"
@@ -24612,21 +24869,21 @@ msgstr ""
 "\n"
 
 #: sequencer.c
-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 "并且修改索引和/或工作区\n"
 
 #: sequencer.c
 #, 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"
 "\n"
 "  git rebase --continue\n"
@@ -25087,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)"
@@ -25148,11 +25494,6 @@ msgid_plural "%u bytes/s"
 msgstr[0] "%u 字节/秒"
 msgstr[1] "%u 字节/秒"
 
-#: strbuf.c
-#, c-format
-msgid "could not edit '%s'"
-msgstr "不能编辑 '%s'"
-
 #: submodule-config.c
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
@@ -27244,14 +27585,19 @@ msgstr "(%s) 不能执行 '%s'"
 
 #: git-send-email.perl
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) 添加 %s: %s 自:'%s'\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) 非法的输出信息,来自于: '%s'"
 
 #: git-send-email.perl
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) 无法关闭管道至 '%s'"
 
+#: git-send-email.perl
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) 添加 %s: %s 自:'%s'\n"
+
 #: git-send-email.perl
 msgid "cannot send message as 7bit"
 msgstr "不能以 7bit 形式发送信息"
index aa59a8e93334a8c9060646569404af2191304d8f..6ae75e7e19f7db0fd7e2bec03619f616efb2734b 100644 (file)
 # - Yichao Yu <yyc1992 AT gmail.com>
 # - Zhuang Ya <zhuangya AT me.com>
 #
-# Yi-Jyun Pan <pan93412@gmail.com>, 2021, 2022.
+# 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: 2022-12-11 00:28+0800\n"
-"PO-Revision-Date: 2022-12-10 17:12+0000\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: Weblate 4.14.2\n"
+"X-Generator: Poedit 3.3.2\n"
 "X-ZhConverter: 繁化姬 dict-f4bc617e-r910 @ 2019/11/16 20:23:12 | https://"
 "zhconvert.org\n"
 
@@ -48,19 +49,19 @@ msgstr "嗯(%s)?"
 msgid "could not read index"
 msgstr "無法讀取索引"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "binary"
 msgstr "二進位"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "nothing"
 msgstr "無"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "unchanged"
 msgstr "未變更"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Update"
 msgstr "更新"
 
@@ -73,14 +74,14 @@ msgstr "無法暫存 “%s”"
 msgid "could not write index"
 msgstr "無法寫入索引"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "已更新 %d 個路徑\n"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "註:現已不再追蹤 %s。\n"
 
@@ -89,7 +90,7 @@ msgstr "註:現已不再追蹤 %s。\n"
 msgid "make_cache_entry failed for path '%s'"
 msgstr "對 “%s” 路徑執行 make_cache_entry 失敗"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Revert"
 msgstr "還原"
 
@@ -97,23 +98,23 @@ msgstr "還原"
 msgid "Could not parse HEAD^{tree}"
 msgstr "無法解析 HEAD^{tree}"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "已還原 %d 個路徑\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 #, c-format
 msgid "No untracked files.\n"
 msgstr "沒有未追蹤的檔案。\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Add untracked"
 msgstr "加入未追蹤項目"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "已加入 %d 個路徑\n"
@@ -123,21 +124,21 @@ msgstr[0] "已加入 %d 個路徑\n"
 msgid "ignoring unmerged: %s"
 msgstr "忽略未合併項目:%s"
 
-#: add-interactive.c add-patch.c git-add--interactive.perl
+#: add-interactive.c add-patch.c
 #, c-format
 msgid "Only binary files changed.\n"
-msgstr "只變更二進位檔案。\n"
+msgstr "只有二進位檔案更動了。\n"
 
-#: add-interactive.c add-patch.c git-add--interactive.perl
+#: add-interactive.c add-patch.c
 #, c-format
 msgid "No changes.\n"
 msgstr "沒有更動。\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Patch update"
 msgstr "修補檔更新"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Review diff"
 msgstr "檢閱差異"
 
@@ -205,25 +206,25 @@ msgstr "選取編號過的項目"
 msgid "(empty) select nothing"
 msgstr "(空)全部不選取"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 msgid "*** Commands ***"
 msgstr "*** 命令 ***"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 msgid "What now"
 msgstr "請選擇"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "staged"
 msgstr "已暫存"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "unstaged"
 msgstr "未暫存"
 
 #: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
-#: builtin/diagnose.c builtin/fetch.c builtin/merge.c builtin/pull.c
-#: builtin/submodule--helper.c git-add--interactive.perl
+#: builtin/diagnose.c builtin/fetch.c builtin/hook.c builtin/merge.c
+#: builtin/pull.c builtin/submodule--helper.c
 msgid "path"
 msgstr "路徑"
 
@@ -231,28 +232,28 @@ msgstr "路徑"
 msgid "could not refresh index"
 msgstr "無法重新整理索引"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 #, c-format
 msgid "Bye.\n"
 msgstr "再見。\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "暫存模式更動 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "暫存刪除動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "暫存加入動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "暫存此區塊 [y,n,q,a,d%s,?]? "
 
@@ -276,23 +277,23 @@ msgstr ""
 "a - 暫存此區塊和本檔案中後面的全部區塊\n"
 "d - 不暫存此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "貯存模式更動 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "貯存刪除動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "貯存加入動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "貯存此區塊 [y,n,q,a,d%s,?]? "
 
@@ -316,23 +317,23 @@ msgstr ""
 "a - 貯存此區塊和本檔案中後面的全部區塊\n"
 "d - 不貯存此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "取消暫存模式更動 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "取消暫存刪除動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "取消暫存加入動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "取消暫存此區塊 [y,n,q,a,d%s,?]? "
 
@@ -356,23 +357,23 @@ msgstr ""
 "a - 不暫存此區塊和本檔案中後面的全部區塊\n"
 "d - 不要不暫存此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "將模式更動套用到索引 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "將刪除動作套用至索引 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "將加入動作套用至索引 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "將此區塊套用到索引 [y,n,q,a,d%s,?]? "
 
@@ -396,23 +397,23 @@ msgstr ""
 "a - 套用此區塊和本檔案中後面的全部區塊\n"
 "d - 不要套用此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "從工作區捨棄模式更動 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "從工作區捨棄刪除動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "從工作區捨棄加入動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "從工作區捨棄此區塊 [y,n,q,a,d%s,?]? "
 
@@ -436,23 +437,23 @@ msgstr ""
 "a - 捨棄此區塊和本檔案中後面的全部區塊\n"
 "d - 不要捨棄此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "從索引和工作區捨棄模式更動 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "從索引和工作區捨棄刪除 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "從索引和工作區捨棄加入動作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "從索引和工作區捨棄此區塊 [y,n,q,a,d%s,?]? "
 
@@ -470,23 +471,23 @@ msgstr ""
 "a - 捨棄此區塊和本檔案中後面的全部區塊\n"
 "d - 不要捨棄此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "將模式更動套用到索引和工作區 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "將刪除動作套用到索引和工作區 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "將加入動作套用到索引和工作區 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "將此區塊套用到索引和工作區 [y,n,q,a,d%s,?]? "
 
@@ -504,23 +505,23 @@ msgstr ""
 "a - 套用此區塊和本檔案中後面的全部區塊\n"
 "d - 不要套用此區塊和本檔案中後面的全部區塊\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "將模式更動套用到工作區 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "將刪除動作套用到工作區 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "將加入動作套用到工作區 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "將此區塊套用到工作區 [y,n,q,a,d%s,?]? "
 
@@ -590,7 +591,7 @@ msgstr ""
 "\t結尾不是:\n"
 "%.*s"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
 msgstr "手動區塊編輯模式——檢視底部的快速指引。\n"
 
@@ -607,9 +608,7 @@ msgstr ""
 "要刪除 “%c” 開頭的列,請直接刪除。\n"
 "開頭是 %c 的列將會被移除。\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 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"
@@ -627,21 +626,13 @@ msgstr "無法解析區塊標頭"
 msgid "'git apply --cached' failed"
 msgstr "“git apply --cached” 失敗"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr "未套用您編輯的區塊。是否重新編輯(輸入 “no” 捨棄!) [y/n]? "
@@ -650,11 +641,11 @@ msgstr "未套用您編輯的區塊。是否重新編輯(輸入 “no” 捨
 msgid "The selected hunks do not apply to the index!"
 msgstr "選取的區塊無法套用至索引!"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Apply them to the worktree anyway? "
 msgstr "無論如何都要套用到工作區嗎? "
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Nothing was applied.\n"
 msgstr "未套用。\n"
 
@@ -692,11 +683,11 @@ msgstr "沒有下一個區塊"
 msgid "No other hunks to goto"
 msgstr "沒有其它可以跳轉的區塊"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "go to which hunk (<ret> to see more)? "
 msgstr "要跳轉到哪個區塊(<ret> 檢視更多)? "
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "go to which hunk? "
 msgstr "跳轉到哪個區塊? "
 
@@ -715,7 +706,7 @@ msgstr[0] "對不起,只有 %d 個可用區塊。"
 msgid "No other hunks to search"
 msgstr "沒有其它可以尋找的區塊"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "search for regex? "
 msgstr "使用常規表示式搜尋? "
 
@@ -780,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 ""
@@ -808,6 +798,24 @@ msgstr "請在合併前先提交您的更動。"
 msgid "Exiting because of unfinished merge."
 msgstr "存在未完成的合併,離開。"
 
+#: advice.c
+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 ""
+"岔開的分支不能快轉,您得執行:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"或者:\n"
+"\n"
+"\tgit rebase\n"
+
 #: advice.c
 msgid "Not possible to fast-forward, aborting."
 msgstr "無法快轉,中止。"
@@ -933,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"
@@ -1295,7 +1311,7 @@ msgstr "無法對剛建立的檔案 %s 建立後端儲存"
 msgid "unable to add cache entry for %s"
 msgstr "無法為 %s 加入快取項目"
 
-#: apply.c builtin/bisect--helper.c builtin/gc.c
+#: apply.c builtin/bisect.c builtin/gc.c
 #, c-format
 msgid "failed to write to '%s'"
 msgstr "無法寫入 “%s”"
@@ -1335,6 +1351,11 @@ msgstr "正在將 .rej 檔案名稱截短為 %.*s.rej"
 msgid "cannot open %s"
 msgstr "無法開啟 %s"
 
+#: apply.c rerere.c
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "無法刪除 “%s”"
+
 #: apply.c
 #, c-format
 msgid "Hunk #%d applied cleanly."
@@ -1569,6 +1590,11 @@ msgstr "git archive --remote <repo> [--exec <cmd>] --list"
 msgid "cannot read '%s'"
 msgstr "無法讀取 “%s”"
 
+#: archive.c
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "符合路徑規格 “%s” 的檔案在目前目錄之外"
+
 #: archive.c builtin/add.c builtin/rm.c
 #, c-format
 msgid "pathspec '%s' did not match any files"
@@ -1589,10 +1615,6 @@ msgstr "非有效物件名稱:%s"
 msgid "not a tree object: %s"
 msgstr "非樹狀物件:%s"
 
-#: archive.c
-msgid "current working directory is untracked"
-msgstr "尚未追蹤目前的工作目錄"
-
 #: archive.c
 #, c-format
 msgid "File not found: %s"
@@ -1626,7 +1648,7 @@ msgstr "fmt"
 msgid "archive format"
 msgstr "封存格式"
 
-#: archive.c builtin/log.c
+#: archive.c builtin/log.c parse-options.h
 msgid "prefix"
 msgstr "前綴"
 
@@ -1660,6 +1682,15 @@ msgstr "讀取工作目錄中的 .gitattributes"
 msgid "report archived files on stderr"
 msgstr "在 stderr 上回報封存的檔案"
 
+#: archive.c builtin/clone.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c
+msgid "time"
+msgstr "time"
+
+#: archive.c
+msgid "set modification time of archive entries"
+msgstr "設定封存項目的修改時間"
+
 #: archive.c
 msgid "set compression level"
 msgstr "設定壓縮級別"
@@ -1715,6 +1746,15 @@ msgstr "引數不支援 “%s” 格式:-%d"
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s 不是有效的屬性名稱"
 
+#: attr.c
+msgid "unable to add additional attribute"
+msgstr "無法加入其他屬性"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "忽略過長的屬性列 (第 %d 列)"
+
 #: attr.c
 #, c-format
 msgid "%s not allowed: %s:%d"
@@ -1728,6 +1768,25 @@ msgstr ""
 "git attributes 會忽略反向模式\n"
 "當字串確定要以驚嘆號開始時,請使用 “\\!”。"
 
+#: attr.c
+#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "無法 fstat gitattributes 檔案 “%s”"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "忽略過大的 gitattributes 檔案 “%s”"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "忽略過大的 gitattributes 資料物件 “%s”"
+
+#: attr.c
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "無效的 --attr-source 或 GIT_ATTR_SOURCE"
+
 #: bisect.c
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
@@ -1849,17 +1908,13 @@ msgstr[0] "二分搜尋中:在此 (%2$s) 之後,尚餘 %1$d 個版本待測
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents 和 --reverse 不能混用。"
 
-#: blame.c
-msgid "cannot use --contents with final commit object name"
-msgstr "無法將 --contents 與最終的提交物件名稱共用"
-
 #: blame.c
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c pack-bitmap.c
-#: ref-filter.c remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c remote.c
+#: sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "修訂版遍歷設定失敗"
 
@@ -1934,12 +1989,10 @@ msgid "not tracking: ambiguous information for ref '%s'"
 msgstr "未追蹤:“%s” 引用有歧義"
 
 #  譯者:為保證在輸出中對齊,注意調整句中空格!
-#. #-#-#-#-#  branch.c.po  #-#-#-#-#
 #. TRANSLATORS: This is a line listing a remote with duplicate
 #. refspecs in the advice message below. For RTL languages you'll
 #. probably want to swap the "%s" and leading "  " space around.
 #.
-#. #-#-#-#-#  object-name.c.po  #-#-#-#-#
 #. TRANSLATORS: This is line item of ambiguous object output
 #. from describe_ambiguous_object() above. For RTL languages
 #. you'll probably want to swap the "%s" and leading " " space
@@ -1985,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
@@ -2040,11 +2093,11 @@ msgstr "“%s” 子模組:找不到子模組"
 #: branch.c
 #, 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 ""
-"您可以嘗試使用 “git checkout %s && git submodule update --init” 命令,更新子"
-"模組"
+"您可以使用 “git checkout --no-recurse-submodules %s && git submodule update "
+"--init” 命令嘗試更新子模組"
 
 #: branch.c
 #, c-format
@@ -2056,11 +2109,6 @@ msgstr "“%s” 子模組:無法建立 “%s” 分支"
 msgid "'%s' is already checked out at '%s'"
 msgstr "“%s” 已在 “%s” 點簽出"
 
-#: branch.c
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "%s 工作區的 HEAD 指針未被更新"
-
 #: builtin/add.c
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<options>] [--] <pathspec>..."
@@ -2070,24 +2118,18 @@ 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 "重新整理索引之後,尚未被暫存的更動:"
 
+#: builtin/add.c
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"add.interactive.useBuiltin 設定已被移除!\n"
+"深入了解請參閱 “git help config” 中的對應條目。"
+
 #: builtin/add.c builtin/rev-parse.c
 msgid "Could not read the index"
 msgstr "無法讀取索引"
@@ -2323,7 +2365,7 @@ msgstr "fseek 失敗"
 msgid "could not open '%s' for reading"
 msgstr "無法開啟 “%s” 進行讀取"
 
-#: builtin/am.c builtin/rebase.c sequencer.c strbuf.c wrapper.c
+#: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "無法開啟 “%s” 進行寫入"
@@ -2545,7 +2587,7 @@ msgstr ""
 "您似乎在上一次 “am” 失敗後移動了 HEAD。\n"
 "未倒轉回 ORIG_HEAD"
 
-#: builtin/am.c builtin/bisect--helper.c worktree.c
+#: builtin/am.c builtin/bisect.c worktree.c
 #, c-format
 msgid "failed to read '%s'"
 msgstr "無法讀取 “%s”"
@@ -2567,6 +2609,10 @@ msgstr "git am [<options>] (--continue | --skip | --abort)"
 msgid "run interactively"
 msgstr "互動式執行"
 
+#: builtin/am.c
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "繞過 pre-applypatch 和 applypatch-msg 掛鉤"
+
 #: builtin/am.c
 msgid "historical option -- no-op"
 msgstr "歷史遺留選項——無作用"
@@ -2586,7 +2632,7 @@ msgstr "在提交說明結尾處加入 Signed-off-by"
 
 #: builtin/am.c
 msgid "recode into utf8 (default)"
-msgstr "使用 utf8 字元集(預設)"
+msgstr "使用 utf8 字元集(預設)"
 
 #: builtin/am.c
 msgid "pass -k flag to git-mailinfo"
@@ -2604,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 "截掉裁切線前的所有內容"
@@ -2756,111 +2798,105 @@ msgstr "git archive:通訊協定錯誤"
 msgid "git archive: expected a flush"
 msgstr "git archive:預期收到 flush 封包"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<commit>]"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 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> --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>...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
+#: builtin/bisect.c
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<rev>...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<rev>...]"
+#: builtin/bisect.c
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<rev>|<range>)...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <filename>"
+#: builtin/bisect.c
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<commit>]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
+#: builtin/bisect.c
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <logfile>"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <cmd>..."
+#: builtin/bisect.c
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <cmd>..."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
 msgstr "無法以 “%2$s” 模式開啟 “%1$s” 檔案"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "could not write to file '%s'"
 msgstr "無法寫入 “%s” 檔案"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for reading"
 msgstr "無法開啟 “%s” 檔案進行讀取"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid term"
 msgstr "“%s” 不是有效術語"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "can't use the builtin command '%s' as a term"
 msgstr "不能將內建命令 “%s” 當作術語使用"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "can't change the meaning of the term '%s'"
 msgstr "不能變更術語 “%s” 的含義"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "please use two different terms"
 msgstr "請使用兩個不同的術語"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "We are not bisecting.\n"
 msgstr "我們沒有在二分搜尋。\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid commit"
 msgstr "“%s” 不是有效的提交"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
 msgstr "不能簽出原始 HEAD “%s”。請嘗試 “git bisect reset <commit>”。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad bisect_write argument: %s"
 msgstr "bisect_write 引數無效:%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't get the oid of the rev '%s'"
 msgstr "無法取得修訂版 “%s” 的物件 ID"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't open the file '%s'"
 msgstr "無法開啟檔案 “%s”"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Invalid command: you're currently in a %s/%s bisect"
 msgstr "命令無效:您目前正處於二分搜尋 %s/%s 的狀態"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to give me at least one %s and %s revision.\n"
@@ -2869,7 +2905,7 @@ msgstr ""
 "需指定至少一個 %s 和一個 %s 修訂版。\n"
 "為此您可以用 “git bisect %s” 和 “git bisect %s”。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to start by \"git bisect start\".\n"
@@ -2880,7 +2916,7 @@ msgstr ""
 "接著提供至少一個 %s 和一個 %s 修訂版。\n"
 "為此您可以用 “git bisect %s” 和 “git bisect %s”。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "bisecting only with a %s commit"
 msgstr "在只有一個 %s 提交的情況下二分搜尋"
@@ -2890,29 +2926,29 @@ msgstr "在只有一個 %s 提交的情況下二分搜尋"
 #. translation. The program will only accept English input
 #. at this point.
 #.
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Are you sure [Y/n]? "
 msgstr "是否確定 [Y/n]? "
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "status: waiting for both good and bad commits\n"
 msgstr "狀態:正在等待好和壞的提交\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "status: waiting for bad commit, %d good commit known\n"
 msgid_plural "status: waiting for bad commit, %d good commits known\n"
 msgstr[0] "狀態:正在等待壞的提交,已知有 %d 個好的提交\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "status: waiting for good commit(s), bad commit known\n"
 msgstr "狀態:正在等待好的提交,已知有壞的提交\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "no terms defined"
 msgstr "未定義術語"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "Your current terms are %s for the old state\n"
@@ -2921,7 +2957,7 @@ msgstr ""
 "您目前針對舊狀態的術語是 %s;\n"
 "對新狀態的術語是 %s。\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "invalid argument %s for 'git bisect terms'.\n"
@@ -2930,52 +2966,48 @@ msgstr ""
 "傳入 “git bisect terms” 的 %s 引數無效。\n"
 "支援的選項有:--term-good|--term-old 和 --term-bad|--term-new。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "revision walk setup failed\n"
 msgstr "修訂版遍歷設定失敗\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "無法開啟 “%s” 進行附加"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "'' is not a valid term"
 msgstr "“ ” 不是有效術語"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "unrecognized option: '%s'"
 msgstr "無法識別選項:“%s”"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' does not appear to be a valid revision"
 msgstr "“%s” 似乎不是有效修訂版"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bad HEAD - I need a HEAD"
 msgstr "HEAD 無效 — 需要一個 HEAD"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
 msgstr "簽出 “%s” 失敗。請嘗試 “git bisect start <valid-branch>”。"
 
-#: builtin/bisect--helper.c
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "不會在做了 cg-seek 的樹狀物件上進行二分搜尋"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bad HEAD - strange symbolic ref"
 msgstr "HEAD 無效 — 異常符號引用"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "invalid ref: '%s'"
 msgstr "引用無效:“%s”"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "You need to start by \"git bisect start\"\n"
 msgstr "要開始,請執行 “git bisect start”\n"
 
@@ -2984,151 +3016,159 @@ msgstr "要開始,請執行 “git bisect start”\n"
 #. translation. The program will only accept English input
 #. at this point.
 #.
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Do you want me to do it for you [Y/n]? "
 msgstr "是否要這麼做 [Y/n]? "
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Please call `--bisect-state` with at least one argument"
 msgstr "要呼叫 `--bisect-state`,請傳入一個以上的引數"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'git bisect %s' can take only one argument."
 msgstr "“git bisect %s” 只取一個引數。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input: %s"
 msgstr "rev 輸入格式錯誤:%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input (not a commit): %s"
 msgstr "rev 輸入有誤(不是提交):%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "We are not bisecting."
 msgstr "我們沒有在二分搜尋。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s'?? what are you talking about?"
 msgstr "「%s」??您在說什麼?"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot read file '%s' for replaying"
 msgstr "無法讀取「%s」檔案進行重放"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "running %s\n"
 msgstr "正在執行 %s\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bisect run failed: no command provided."
 msgstr "二分搜尋執行失敗:沒有提供命令。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "無法在好的修訂版上驗證 “%s”"
+msgid "unable to verify %s on good revision"
+msgstr "無法在好的修訂版上驗證 %s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "好的修訂版回傳偽造的錯誤碼 %d"
 
-#: builtin/bisect--helper.c
+#: 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"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "二分搜尋執行失敗:%2$s 回傳的結束代碼 %1$d 小於 0 或大於 128"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for writing"
 msgstr "無法開啟 “%s” 檔案進行寫入"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bisect run cannot continue any more"
 msgstr "二分搜尋不能繼續執行"
 
-#: builtin/bisect--helper.c
-#, c-format
+#: builtin/bisect.c
 msgid "bisect run success"
 msgstr "二分搜尋執行成功"
 
-#: builtin/bisect--helper.c
-#, c-format
+#: builtin/bisect.c
 msgid "bisect found first bad commit"
 msgstr "二分搜尋發現到第一個有問題的提交"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"二分搜尋執行失敗:“git bisect--helper --bisect-state %s” 以錯誤碼 %d 離開"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "二分搜尋執行失敗:“git bisect %s” 以錯誤碼 %d 離開"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset 可以不需要引數,或者得傳入一個提交"
-
-#: builtin/bisect--helper.c
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms 需要 0 或 1 個引數"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "“%s” 不需要引數,或者得傳入一個提交"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next 需要 0 個引數"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "“%s” 需要 0 或 1 個引數"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log 需要 0 個引數"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "“%s” 不需引數"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "no logfile given"
 msgstr "未提供日誌檔案"
 
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "“%s” 失敗:沒有提供命令。"
+
+#: builtin/bisect.c
+msgid "need a command"
+msgstr "需要提供命令"
+
+#: builtin/bisect.c builtin/cat-file.c
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "未知命令:“%s”"
+
 #: builtin/blame.c
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
-msgstr "git blame [<選項>] [<版本選項>] [<版本>] [--] <檔案>"
+msgstr "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 
 #: builtin/blame.c
 msgid "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
-msgstr "git annotate [<選項>] [<版本選項>] [<版本>] [--] <檔案>"
+msgstr "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
 
 #: builtin/blame.c
 msgid "<rev-opts> are documented in git-rev-list(1)"
-msgstr "<版本選項> 的檔案記錄在 git-rev-list(1) 中"
+msgstr "<rev-opts> 的文件在 git-rev-list(1)"
 
 #: builtin/blame.c
 #, c-format
 msgid "expecting a color: %s"
-msgstr "期望一個顏色:%s"
+msgstr "預期是個顏色:%s"
 
 #: builtin/blame.c
 msgid "must end with a color"
-msgstr "必須以一個顏色結尾"
+msgstr "結尾必須是一個顏色"
 
 #: builtin/blame.c
 #, c-format
 msgid "cannot find revision %s to ignore"
-msgstr "不能找到要忽略的版本 %s"
+msgstr "不能找到要忽略的 %s 修訂版"
 
 #: builtin/blame.c
 msgid "show blame entries as we find them, incrementally"
-msgstr "增量式顯示發現的 blame 條目"
+msgstr "漸進式顯示發現的溯源項目"
 
 #: builtin/blame.c
 msgid "do not show object names of boundary commits (Default: off)"
-msgstr "不要顯示邊界提交的物件名稱(預設值off)"
+msgstr "不要顯示邊界提交的物件名稱(預設值off)"
 
 #: builtin/blame.c
 msgid "do not treat root commits as boundaries (Default: off)"
-msgstr "不將根提交看作邊界(預設值:off)"
+msgstr "不把根提交當作邊界(預設值:off)"
 
 #: builtin/blame.c
 msgid "show work cost statistics"
@@ -3142,7 +3182,7 @@ msgstr "強制顯示進度報告"
 
 #: builtin/blame.c
 msgid "show output score for blame entries"
-msgstr "顯示判斷 blame 條目位移的得分診斷訊息"
+msgstr "顯示溯源項目的輸出得分"
 
 #: builtin/blame.c
 msgid "show original filename (Default: auto)"
@@ -3150,7 +3190,7 @@ msgstr "顯示原始檔案名稱(預設值:auto)"
 
 #: builtin/blame.c
 msgid "show original linenumber (Default: off)"
-msgstr "顯示原始檔案名稱(預設值:off)"
+msgstr "顯示原始列碼(預設值:off)"
 
 #: builtin/blame.c
 msgid "show in a format designed for machine consumption"
@@ -3158,7 +3198,7 @@ msgstr "顯示成適合機器讀取的格式"
 
 #: builtin/blame.c
 msgid "show porcelain format with per-line commit information"
-msgstr "顯示每一列適合機器的提交說明"
+msgstr "顯示包含每一列提交資訊,適合機器讀取的格式"
 
 #: builtin/blame.c
 msgid "use the same output mode as git-annotate (Default: off)"
@@ -3186,15 +3226,15 @@ msgstr "忽略空白差異"
 
 #: builtin/blame.c builtin/log.c
 msgid "rev"
-msgstr "版本"
+msgstr "rev"
 
 #: builtin/blame.c
 msgid "ignore <rev> when blaming"
-msgstr "在執行 blame 動作時忽略 <修訂版>"
+msgstr "在執行溯源動作時忽略 <rev>"
 
 #: builtin/blame.c
 msgid "ignore revisions from <file>"
-msgstr "忽略 <檔案> 中的修訂版"
+msgstr "忽略 <file> 中的修訂版"
 
 #: builtin/blame.c
 msgid "color redundant metadata from previous line differently"
@@ -3202,31 +3242,31 @@ msgstr "使用顏色間隔輸出與前一行不同的重複中介資料"
 
 #: builtin/blame.c
 msgid "color lines by age"
-msgstr "據時間著色"
+msgstr "據時間著色"
 
 #: builtin/blame.c
 msgid "spend extra cycles to find better match"
-msgstr "循ç\92°æ\9b´å¤\9a次以æ\89¾å\88°æ\9b´ä½³ç¬¦å\90\88"
+msgstr "循ç\92°æ\9b´å¤\9a次ä¾\86æ\89¾å\88°æ\9b´ä½³ç¬¦å\90\88é \85ç\9b®"
 
 #: builtin/blame.c
 msgid "use revisions from <file> instead of calling git-rev-list"
-msgstr "使用來自 <檔案> 的修訂集而不是呼叫 git-rev-list"
+msgstr "使用來自 <file> 的修訂集而不是呼叫 git-rev-list"
 
 #: builtin/blame.c
 msgid "use <file>'s contents as the final image"
-msgstr "將 <檔案> 的內容當成是最終 image"
+msgstr "將 <file> 的內容當成是最終印象"
 
 #: builtin/blame.c
 msgid "score"
-msgstr "得分"
+msgstr "score"
 
 #: builtin/blame.c
 msgid "find line copies within and across files"
-msgstr "找到檔案內及跨檔案的複製列"
+msgstr "找到檔案內及跨檔案的列拷貝動作"
 
 #: builtin/blame.c
 msgid "find line movements within and across files"
-msgstr "找到檔案內及跨檔案的移動列"
+msgstr "找到檔案內及跨檔案的列移動動作"
 
 #: builtin/blame.c
 msgid "range"
@@ -3256,45 +3296,47 @@ msgstr "4 年 11 個月前"
 #, c-format
 msgid "file %s has only %lu line"
 msgid_plural "file %s has only %lu lines"
-msgstr[0] "檔案 %s 只有 %lu "
+msgstr[0] "檔案 %s 只有 %lu "
 
 #: builtin/blame.c
 msgid "Blaming lines"
-msgstr "追蹤程式碼行"
+msgstr "溯源文字列"
 
 #: builtin/branch.c
 msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
-msgstr "git branch [<選項>] [-r | -a] [--merged] [--no-merged]"
+msgstr "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
 
 #: builtin/branch.c
 msgid ""
 "git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
 "point>]"
-msgstr "git branch [<選項>] [-f] [--recurse-submodules] <分支名> [<起始點>]"
+msgstr ""
+"git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
+"point>]"
 
 #: builtin/branch.c
 msgid "git branch [<options>] [-l] [<pattern>...]"
-msgstr "git branch [<選項>] [-l] [<模式>...]"
+msgstr "git branch [<options>] [-l] [<pattern>...]"
 
 #: builtin/branch.c
 msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..."
-msgstr "git branch [<選項>] [-r] (-d | -D) <分支名>..."
+msgstr "git branch [<options>] [-r] (-d | -D) <branch-name>..."
 
 #: builtin/branch.c
 msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
-msgstr "git branch [<選項>] (-m | -M) [<舊分支>] <新分支>"
+msgstr "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
 
 #: builtin/branch.c
 msgid "git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"
-msgstr "git branch [<選項>] (-c | -C) [<老分支>] <新分支>"
+msgstr "git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"
 
 #: builtin/branch.c
 msgid "git branch [<options>] [-r | -a] [--points-at]"
-msgstr "git branch [<選項>] [-r | -a] [--points-at]"
+msgstr "git branch [<options>] [-r | -a] [--points-at]"
 
 #: builtin/branch.c
 msgid "git branch [<options>] [-r | -a] [--format]"
-msgstr "git branch [<選項>] [-r | -a] [--format]"
+msgstr "git branch [<options>] [-r | -a] [--format]"
 
 #  譯者:保持原換行格式,在輸出時 %s 的替代內容會讓字串變長
 #: builtin/branch.c
@@ -3303,8 +3345,8 @@ msgid ""
 "deleting branch '%s' that has been merged to\n"
 "         '%s', but not yet merged to HEAD."
 msgstr ""
-"將要刪除的分支 '%s' 已經被合併到\n"
-"         '%s',但未合併到 HEAD。"
+"將要刪除的 “%s” 分支已經被合併到\n"
+"         “%s”,但尚未合併到 HEAD。"
 
 #  譯者:保持原換行格式,在輸出時 %s 的替代內容會讓字串變長
 #: builtin/branch.c
@@ -3313,13 +3355,13 @@ msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
 "         '%s', even though it is merged to HEAD."
 msgstr ""
-"並未刪除分支 '%s', 雖然它已經合併到 HEAD,\n"
-"         然而卻尚未被合併到分支 '%s' 。"
+"並未刪除分支 “%s”, 雖然已經合併到 HEAD,\n"
+"         卻尚未被合併至 “%s” 分支。"
 
 #: builtin/branch.c
 #, c-format
 msgid "Couldn't look up commit object for '%s'"
-msgstr "無法查詢 '%s' 指向的提交物件"
+msgstr "無法查詢 “%s” 指向的提交物件"
 
 #: builtin/branch.c
 #, c-format
@@ -3327,12 +3369,12 @@ 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'。"
+"分支 “%s” 沒有完全合併。\n"
+"如果確定要刪除它,請執行 “git branch -D %s”。"
 
 #: builtin/branch.c
 msgid "Update of config-file failed"
-msgstr "更新設定檔案失敗"
+msgstr "更新組態檔案失敗"
 
 #: builtin/branch.c
 msgid "cannot use -a with -d"
@@ -3341,17 +3383,26 @@ msgstr "不能將 -a 和 -d 同時使用"
 #: builtin/branch.c
 #, c-format
 msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "無法刪除在「%2$s」簽出的「%1$s」分支"
+msgstr "無法刪除在 “%2$s” 簽出的 “%1$s” 分支"
 
 #: builtin/branch.c
 #, c-format
 msgid "remote-tracking branch '%s' not found."
-msgstr "未能找到遠端追蹤分支 '%s'。"
+msgstr "找不到 “%s” 遠端追蹤分支。"
+
+#: builtin/branch.c
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"找不到 “%s” 分支。\n"
+"您可能要加上 --remote?"
 
 #: builtin/branch.c
 #, c-format
 msgid "branch '%s' not found."
-msgstr "分支 '%s' 未發現。"
+msgstr "找不到 “%s” 分支。"
 
 #: builtin/branch.c
 #, c-format
@@ -3365,41 +3416,46 @@ msgstr "已刪除分支 %s(曾為 %s)。\n"
 
 #: builtin/branch.c builtin/tag.c
 msgid "unable to parse format string"
-msgstr "不能解析格式化字串"
+msgstr "無法解析格式化字串"
 
 #: builtin/branch.c
 msgid "could not resolve HEAD"
-msgstr "不能解析 HEAD 提交"
+msgstr "無法解析 HEAD 指針"
 
 #: builtin/branch.c
 #, c-format
 msgid "HEAD (%s) points outside of refs/heads/"
-msgstr "HEAD (%s) 指向 refs/heads/ 之外"
+msgstr "HEAD 指針 (%s) 指向 refs/heads/ 之外"
 
 #: builtin/branch.c
 #, c-format
 msgid "Branch %s is being rebased at %s"
-msgstr "分支 %s 正被重定基底到 %s"
+msgstr "%s 分支正在重定基底至 %s"
 
 #: builtin/branch.c
 #, c-format
 msgid "Branch %s is being bisected at %s"
-msgstr "分支 %s 正被二分搜尋於 %s"
+msgstr "%s 分支正於 %s 進行二分搜尋"
+
+#: builtin/branch.c
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "%s 工作區的 HEAD 指針未被更新"
 
 #: builtin/branch.c
 #, c-format
 msgid "Invalid branch name: '%s'"
-msgstr "無效的分支名:'%s'"
+msgstr "分支名稱無效:“%s”"
 
 #: builtin/branch.c
 #, c-format
 msgid "No commit on branch '%s' yet."
-msgstr "分支 '%s' 尚無提交。"
+msgstr "分支 “%s” 尚無提交。"
 
 #: builtin/branch.c
 #, c-format
 msgid "No branch named '%s'."
-msgstr "æ²\92æ\9c\89å\88\86æ\94¯ '%s'。"
+msgstr "æ²\92æ\9c\89å\90\8dç\82º â\80\9c%sâ\80\9d ç\9a\84å\88\86æ\94¯。"
 
 #: builtin/branch.c
 msgid "Branch rename failed"
@@ -3407,30 +3463,30 @@ msgstr "分支重新命名失敗"
 
 #: builtin/branch.c
 msgid "Branch copy failed"
-msgstr "分支複製失敗"
+msgstr "分支拷貝失敗"
 
 #: builtin/branch.c
 #, c-format
 msgid "Created a copy of a misnamed branch '%s'"
-msgstr "已為錯誤命名的分支 '%s' 建立了一個副本"
+msgstr "已為誤命名的 “%s” 分支建立拷貝"
 
 #: builtin/branch.c
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
-msgstr "已將錯誤命名的分支 '%s' 重新命名"
+msgstr "已更改誤命名的 “%s” 分支的名稱"
 
 #: builtin/branch.c
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "分支重新命名為 %s,但 HEAD 沒有更新!"
+msgstr "分支已重新命名為 %s,但 HEAD 指針尚未更新!"
 
 #: builtin/branch.c
 msgid "Branch is renamed, but update of config-file failed"
-msgstr "分支被重新命名,但更新設定檔案失敗"
+msgstr "分支已重新命名,但無法更新組態檔案"
 
 #: builtin/branch.c
 msgid "Branch is copied, but update of config-file failed"
-msgstr "分支已複製,但更新設定檔案失敗"
+msgstr "分支已拷貝,但無法更新組態檔案"
 
 #: builtin/branch.c
 #, c-format
@@ -3439,41 +3495,41 @@ msgid ""
 "  %s\n"
 "Lines starting with '%c' will be stripped.\n"
 msgstr ""
-"請編輯分支的描述\n"
+"請編輯下述分支的描述\n"
 "  %s\n"
-"以 '%c' 開頭的行將被過濾。\n"
+"開頭是 “%c” 的列將被刪除。\n"
 
 #: builtin/branch.c
 msgid "Generic options"
-msgstr "通用選項"
+msgstr "一般性選項"
 
 #: builtin/branch.c
 msgid "show hash and subject, give twice for upstream branch"
-msgstr "顯示雜湊值和主題,若參數出現兩次則顯示上游分支"
+msgstr "顯示雜湊值和主旨,若傳入兩次則顯示上游分支"
 
 #: builtin/branch.c
 msgid "suppress informational messages"
-msgstr "不顯示訊息"
+msgstr "ä¸\8d顯示è³\87è¨\8aè¨\8aæ\81¯"
 
 #: builtin/branch.c builtin/checkout.c builtin/submodule--helper.c
 msgid "set branch tracking configuration"
-msgstr "設定分支追蹤設定"
+msgstr "設定分支追蹤組態"
 
 #: builtin/branch.c
 msgid "do not use"
-msgstr "不要使用"
+msgstr "請勿使用"
 
 #: builtin/branch.c
 msgid "upstream"
-msgstr "上游"
+msgstr "upstream"
 
 #: builtin/branch.c
 msgid "change the upstream info"
-msgstr "改變上游訊息"
+msgstr "變更上游資訊"
 
 #: builtin/branch.c
 msgid "unset the upstream info"
-msgstr "取消上游資訊設定"
+msgstr "取消設定上游資訊"
 
 #: builtin/branch.c
 msgid "use colored output"
@@ -3485,19 +3541,19 @@ msgstr "作用於遠端追蹤分支"
 
 #: builtin/branch.c
 msgid "print only branches that contain the commit"
-msgstr "只列印包含該提交的分支"
+msgstr "只輸出包含此提交的分支"
 
 #: builtin/branch.c
 msgid "print only branches that don't contain the commit"
-msgstr "只列印不包含該提交的分支"
+msgstr "只輸出不包含此提交的分支"
 
 #: builtin/branch.c
 msgid "Specific git-branch actions:"
-msgstr "具體的 git-branch 動作:"
+msgstr "特定的 git-branch 動作:"
 
 #: builtin/branch.c
 msgid "list both remote-tracking and local branches"
-msgstr "å\88\97å\87ºé\81 ç«¯è¿½è¹¤å\8f\8a本機分支"
+msgstr "å\88\97å\87ºé\81 ç«¯è¿½è¹¤å\92\8c本機分支"
 
 #: builtin/branch.c
 msgid "delete fully merged branch"
@@ -3505,31 +3561,35 @@ msgstr "刪除完全合併的分支"
 
 #: builtin/branch.c
 msgid "delete branch (even if not merged)"
-msgstr "刪除分支(即使沒有合併)"
+msgstr "刪除分支(即使尚未合併)"
 
 #: builtin/branch.c
 msgid "move/rename a branch and its reflog"
-msgstr "移動/重新命名一個分支,以及它的引用日誌"
+msgstr "移動或重新命名分支及其引用日誌"
 
 #: builtin/branch.c
 msgid "move/rename a branch, even if target exists"
-msgstr "移動/重新命名一個分支,即使目標已存在"
+msgstr "即使目標已存在,仍移動或重新命名分支"
+
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
+msgid "do not output a newline after empty formatted refs"
+msgstr "在格式化引用結果為空之後,不要輸出換列符號"
 
 #: builtin/branch.c
 msgid "copy a branch and its reflog"
-msgstr "複製分支及其引用日誌"
+msgstr "拷貝分支及其引用日誌"
 
 #: builtin/branch.c
 msgid "copy a branch, even if target exists"
-msgstr "複製一個分支,即使目標已存在"
+msgstr "即使目標已存在仍拷貝分支"
 
 #: builtin/branch.c
 msgid "list branch names"
-msgstr "列出分支名"
+msgstr "列出分支名"
 
 #: builtin/branch.c
 msgid "show current branch name"
-msgstr "顯示目前分支名"
+msgstr "顯示目前分支名"
 
 #: builtin/branch.c builtin/submodule--helper.c
 msgid "create the branch's reflog"
@@ -3537,7 +3597,7 @@ msgstr "建立分支的引用日誌"
 
 #: builtin/branch.c
 msgid "edit the description for the branch"
-msgstr "標記分支的描述"
+msgstr "編輯分支的描述"
 
 #: builtin/branch.c
 msgid "force creation, move/rename, deletion"
@@ -3545,27 +3605,27 @@ msgstr "強制建立、移動/重新命名、刪除"
 
 #: builtin/branch.c
 msgid "print only branches that are merged"
-msgstr "只列印已經合併的分支"
+msgstr "只輸出已經合併的分支"
 
 #: builtin/branch.c
 msgid "print only branches that are not merged"
-msgstr "只列印尚未合併的分支"
+msgstr "只輸出尚未合併的分支"
 
 #: builtin/branch.c
 msgid "list branches in columns"
-msgstr "以å\88\97ç\9a\84æ\96¹å¼\8f顯示å\88\86æ\94¯"
+msgstr "以è¡\8cç\9a\84å½¢å¼\8få\88\97å\87ºå\88\86æ\94¯"
 
 #: builtin/branch.c builtin/for-each-ref.c builtin/notes.c builtin/tag.c
 msgid "object"
-msgstr "物件"
+msgstr "object"
 
 #: builtin/branch.c
 msgid "print only branches of the object"
-msgstr "只列印指向該物件的分支"
+msgstr "只輸出指向此物件的分支"
 
 #: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
 msgid "sorting and filtering are case insensitive"
-msgstr "排序和過濾屬於大小寫不敏感"
+msgstr "排序和過濾不區分大小寫"
 
 #: builtin/branch.c builtin/ls-files.c
 msgid "recurse through submodules"
@@ -3582,14 +3642,14 @@ msgstr "無法將 HEAD 解析為有效引用。"
 
 #: builtin/branch.c builtin/clone.c
 msgid "HEAD not found below refs/heads!"
-msgstr "HEAD æ²\92æ\9c\89ä½\8dæ\96¼ /refs/heads ä¹\8bä¸\8b!"
+msgstr "HEAD æ\8c\87é\87\9dä¸\8då\9c¨ /refs/heads ä¸­!"
 
 #: builtin/branch.c
 msgid ""
 "branch with --recurse-submodules can only be used if submodule."
 "propagateBranches is enabled"
 msgstr ""
-"有 --recurse-submodules 的分支只能在啟用 submodule.propagateBranches 時使用"
+"有 --recurse-submodules 的分支只能在啟用 submodule.propagateBranches 時使用"
 
 #: builtin/branch.c
 msgid "--recurse-submodules can only be used to create branches"
@@ -3597,79 +3657,79 @@ msgstr "--recurse-submodules 只能用來建立分支"
 
 #: builtin/branch.c
 msgid "branch name required"
-msgstr "必須提供分支名"
+msgstr "必須提供分支名"
 
 #: builtin/branch.c
 msgid "Cannot give description to detached HEAD"
-msgstr "不能向分離開頭指標提供描述"
+msgstr "無法向分離 HEAD 指針提供描述"
 
 #: builtin/branch.c
 msgid "cannot edit description of more than one branch"
-msgstr "不能為一個以上的分支編輯描述"
+msgstr "無法編輯超過一個分支的描述"
 
 #: builtin/branch.c
 msgid "cannot copy the current branch while not on any."
-msgstr "無法複製目前分支因為不處於任何分支上。"
+msgstr "不在任何分支上,無法拷貝目前分支。"
 
 #: builtin/branch.c
 msgid "cannot rename the current branch while not on any."
-msgstr "無法重新命名目前分支因為不處於任何分支上。"
+msgstr "不在任何分支上,無法重新命名目前分支。"
 
 #: builtin/branch.c
 msgid "too many branches for a copy operation"
-msgstr "為複製動作提供了太多的分支名"
+msgstr "要進行拷貝動作的分支太多"
 
 #: builtin/branch.c
 msgid "too many arguments for a rename operation"
-msgstr "為重新命名動作提供了太多的參數"
+msgstr "傳入重新命名動作的引數太多"
 
 #: builtin/branch.c
 msgid "too many arguments to set new upstream"
-msgstr "為設定新上游提供了太多的參數"
+msgstr "要設定新上游的引數太多"
 
 #: builtin/branch.c
 #, c-format
 msgid ""
 "could not set upstream of HEAD to %s when it does not point to any branch."
-msgstr "無法設定 HEAD 的上游為 %s,因為 HEAD 沒有指向任何分支。"
+msgstr "無法將 HEAD 的上游設為 %s:其未指向任何分支。"
 
 #: builtin/branch.c
 #, c-format
 msgid "no such branch '%s'"
-msgstr "沒有此分支 '%s'"
+msgstr "無 “%s” 分支"
 
 #: builtin/branch.c
 #, c-format
 msgid "branch '%s' does not exist"
-msgstr "分支 '%s' 不存在"
+msgstr "沒有 “%s” 分支"
 
 #: builtin/branch.c
 msgid "too many arguments to unset upstream"
-msgstr "為取消上游設定動作提供了太多的參數"
+msgstr "要取消設定上游的引數太多"
 
 #: builtin/branch.c
 msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr "在 HEAD 的上游未指向任何分支時無法取消設定。"
+msgstr "無法取消設定 HEAD 的上游:其未指向任何分支。"
 
 #: builtin/branch.c
 #, c-format
 msgid "Branch '%s' has no upstream information"
-msgstr "分支 '%s' 沒有上游訊息"
+msgstr "分支 “%s” 沒有上游資訊"
 
 #: builtin/branch.c
 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 ""
-"'git branch' 的 -a 和 -r 選項不帶一個分支名。\n"
-"您是否想要使用:-a|-r --list <模式>?"
+"“git branch” 的 -a 和 -r 選項不取分支名稱。\n"
+"您是想使用:-a|-r --list <pattern> 嗎?"
 
 #: builtin/branch.c
 msgid ""
 "the '--set-upstream' option is no longer supported. Please use '--track' or "
 "'--set-upstream-to' instead."
 msgstr ""
-"不再支援選項 '--set-upstream'。請使用 '--track' 或 '--set-upstream-to'。"
+"不再支援選項 “--set-upstream”。請改用 “--track” 或 “--set-upstream-to”。"
 
 #: builtin/bugreport.c
 msgid "git version:\n"
@@ -3678,7 +3738,7 @@ msgstr "git 版本:\n"
 #: builtin/bugreport.c
 #, c-format
 msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() 失敗,錯誤:「%s」(%d)\n"
+msgstr "uname() 失敗,錯誤:“%s” (%d)\n"
 
 #: builtin/bugreport.c
 msgid "compiler info: "
@@ -3690,7 +3750,7 @@ msgstr "libc 資訊: "
 
 #: builtin/bugreport.c
 msgid "not run from a git repository - no hooks to show\n"
-msgstr "ä¸\8dæ\98¯å¾\9e git ç\89\88æ\9c¬åº«å\9f·è¡\8c - 沒有可顯示的掛鉤\n"
+msgstr "ä¸\8dæ\98¯å\9c¨ git ç\89\88æ\9c¬åº«å\9f·è¡\8c â\80\94 沒有可顯示的掛鉤\n"
 
 #: builtin/bugreport.c
 msgid ""
@@ -3719,15 +3779,15 @@ msgid ""
 "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"
 "\n"
@@ -3737,25 +3797,25 @@ msgstr ""
 #: builtin/bugreport.c builtin/commit.c builtin/fast-export.c builtin/rebase.c
 #: parse-options.h
 msgid "mode"
-msgstr "模式"
+msgstr "mode"
 
 #: builtin/bugreport.c
 msgid ""
 "create an additional zip archive of detailed diagnostics (default 'stats')"
-msgstr "建ç«\8b詳細診æ\96·è³\87è¨\8aç\9a\84é¡\8då¤\96 zip å°\81å­\98æª\94æ¡\88ï¼\88é \90設å\80¼æ\98¯ “stats”)"
+msgstr "å\8f¦å¤\96建ç«\8bæ\9c\89詳細診æ\96·è³\87è¨\8aç\9a\84 ZIP å°\81å­\98æª\94ï¼\88é \90設å\80¼ “stats”)"
 
 #: builtin/bugreport.c
 msgid "specify a destination for the bugreport file(s)"
-msgstr "指定臭蟲報告檔案的目的地"
+msgstr "指定臭蟲報告檔案的目的地"
 
 #: builtin/bugreport.c
 msgid "specify a strftime format suffix for the filename(s)"
-msgstr "指定檔名,strftime 格式的後綴"
+msgstr "指定用於檔名的 strftime 格式後綴"
 
 #: builtin/bugreport.c builtin/diagnose.c
 #, c-format
 msgid "could not create leading directories for '%s'"
-msgstr "無法建立 '%s' 的前置目錄"
+msgstr "無法建立 “%s” 的前置目錄"
 
 #: builtin/bugreport.c builtin/diagnose.c
 #, c-format
@@ -3778,16 +3838,14 @@ msgstr "無法寫入 %s"
 #: builtin/bugreport.c
 #, c-format
 msgid "Created new report at '%s'.\n"
-msgstr "已在「%s」建立新報告。\n"
+msgstr "已在 “%s” 建立新報告。\n"
 
 #: builtin/bundle.c
 msgid ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
-"git bundle create [-q | --quiet | --progress | --all-progress] [--all-"
-"progress-implied]\n"
+"git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 
 #: builtin/bundle.c
@@ -3796,27 +3854,31 @@ msgstr "git bundle verify [-q | --quiet] <file>"
 
 #: builtin/bundle.c
 msgid "git bundle list-heads <file> [<refname>...]"
-msgstr "git bundle list-heads <檔案> [<引用名稱>...]"
+msgstr "git bundle list-heads <file> [<refname>...]"
 
 #: builtin/bundle.c
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <file> [<refname>...]"
 
+#: builtin/bundle.c
+msgid "need a <file> argument"
+msgstr "需要提供 <file> 引數"
+
 #: builtin/bundle.c builtin/pack-objects.c
 msgid "do not show progress meter"
-msgstr "不顯示進度"
+msgstr "不顯示進度"
 
 #: builtin/bundle.c builtin/pack-objects.c
 msgid "show progress meter"
-msgstr "顯示進度"
+msgstr "顯示進度"
 
-#: builtin/bundle.c builtin/pack-objects.c
-msgid "show progress meter during object writing phase"
-msgstr "在物件寫入階段顯示進度表"
+#: builtin/bundle.c
+msgid "historical; same as --progress"
+msgstr "歷史遺留選項;和 --progress 相同"
 
-#: builtin/bundle.c builtin/pack-objects.c
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "當進度表顯示時類似於 --all-progress"
+#: builtin/bundle.c
+msgid "historical; does nothing"
+msgstr "歷史遺留選項;沒有作用"
 
 #: builtin/bundle.c
 msgid "specify bundle format version"
@@ -3841,12 +3903,12 @@ msgstr "需要版本庫才能拆分套件包。"
 
 #: builtin/bundle.c
 msgid "Unbundling objects"
-msgstr "正在解包物件"
+msgstr "正在拆分物件"
 
 #: builtin/cat-file.c merge-recursive.c
 #, c-format
 msgid "cannot read object %s '%s'"
-msgstr "不能讀取物件 %s '%s'"
+msgstr "無法讀取物件 %s “%s”"
 
 #: builtin/cat-file.c
 msgid "flush is only for --buffer mode"
@@ -3859,7 +3921,7 @@ msgstr "輸入中沒有命令"
 #: builtin/cat-file.c
 #, c-format
 msgid "whitespace before command: '%s'"
-msgstr "命令前空格:「%s」"
+msgstr "命令前有空格:“%s”"
 
 #: builtin/cat-file.c
 #, c-format
@@ -3871,11 +3933,6 @@ msgstr "%s 需要引數"
 msgid "%s takes no arguments"
 msgstr "%s 不取引數"
 
-#: builtin/cat-file.c
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "未知命令:「%s」"
-
 #: builtin/cat-file.c
 msgid "only one batch option may be specified"
 msgstr "只能指定一個批次處理選項"
@@ -3897,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 ""
@@ -3926,7 +3983,7 @@ msgstr "美化輸出 <object> 的內容"
 
 #: builtin/cat-file.c
 msgid "Emit [broken] object attributes"
-msgstr "輸出 [損壞的] 物件屬性"
+msgstr "輸出 [損壞的] ([broken]) 物件屬性"
 
 #: builtin/cat-file.c
 msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
@@ -3958,15 +4015,19 @@ msgstr "類似 --batch 但不輸出 <contents>"
 
 #: builtin/cat-file.c
 msgid "stdin is NUL-terminated"
-msgstr "標準輸入以 NUL 字元終止"
+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 "從標準輸入讀取命令"
+msgstr "從 stdin 讀取命令"
 
 #: builtin/cat-file.c
 msgid "with --batch[-check]: ignores stdin, batches all known objects"
-msgstr "傳入 --batch[-check]:忽略標準輸入,批次處理所有已知物件"
+msgstr "傳入 --batch[-check]:忽略 stdin,批次處理所有已知物件"
 
 #: builtin/cat-file.c
 msgid "Change or optimize batch output"
@@ -3978,21 +4039,21 @@ msgstr "緩衝 --batch 的輸出"
 
 #: builtin/cat-file.c
 msgid "follow in-tree symlinks"
-msgstr "追蹤樹中的符號連結"
+msgstr "追蹤樹狀物件中的符號連結"
 
 #: builtin/cat-file.c
 msgid "do not order objects before emitting them"
-msgstr "不要在輸出物件前排序"
+msgstr "不要在輸出前排序物件"
 
 #: builtin/cat-file.c
 msgid ""
 "Emit object (blob or tree) with conversion or filter (stand-alone, or with "
 "batch)"
-msgstr "轉換或過濾後輸出物件(blob 或樹)(單獨或批次處理)"
+msgstr "轉換或過濾後輸出物件 (blob 或 tree)(單獨或批次處理)"
 
 #: builtin/cat-file.c
 msgid "run textconv on object's content"
-msgstr "å\9c¨ç\89©ä»¶å\85§å®¹å\9f·è¡\8c textconv"
+msgstr "å°\8dç\89©ä»¶å\85§å®¹é\80²è¡\8cæ\96\87å­\97è½\89æ\8f\9b (textconv)"
 
 #: builtin/cat-file.c
 msgid "run filters on object's content"
@@ -4009,7 +4070,7 @@ msgstr "請在 (--textconv | --filters) 使用 <path>,而非 “batch”"
 #: builtin/cat-file.c
 #, c-format
 msgid "'%s=<%s>' needs '%s' or '%s'"
-msgstr "「%s=<%s>」需要「%s」或「%s」"
+msgstr "“%s=<%s>” 需要 “%s” 或 “%s”"
 
 #: builtin/cat-file.c
 msgid "path|tree-ish"
@@ -4018,12 +4079,12 @@ msgstr "path|tree-ish"
 #: builtin/cat-file.c
 #, c-format
 msgid "'%s' requires a batch mode"
-msgstr "「%s」需要批次處理模式"
+msgstr "“%s” 需要批次處理模式"
 
 #: builtin/cat-file.c
 #, c-format
 msgid "'-%c' is incompatible with batch mode"
-msgstr "「-%c」與批次處理模式不相容"
+msgstr "“-%c” 與批次處理模式不相容"
 
 #: builtin/cat-file.c
 msgid "batch modes take no arguments"
@@ -4032,12 +4093,12 @@ msgstr "批次處理模式不取引數"
 #: builtin/cat-file.c
 #, c-format
 msgid "<rev> required with '%s'"
-msgstr "<rev> 需要搭配「%s」"
+msgstr "“%s” 需要 <rev>"
 
 #: builtin/cat-file.c
 #, c-format
 msgid "<object> required with '-%c'"
-msgstr "<object> 需要搭配「-%c」"
+msgstr "“-%c” 需要 <object>"
 
 #: builtin/cat-file.c
 #, c-format
@@ -4045,16 +4106,22 @@ msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "只允許在 <type> <object> 模式傳入兩個引數,但傳了 %d 個"
 
 #: builtin/check-attr.c
-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 ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
 
 #: builtin/check-attr.c
-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 ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
 
 #: builtin/check-attr.c
 msgid "report all attributes set on file"
-msgstr "å ±å\91\8a設定在檔案上的所有屬性"
+msgstr "å\9b\9eå ±設定在檔案上的所有屬性"
 
 #: builtin/check-attr.c
 msgid "use .gitattributes only from the index"
@@ -4062,11 +4129,19 @@ msgstr "只使用索引中的 .gitattributes"
 
 #: builtin/check-attr.c builtin/check-ignore.c builtin/hash-object.c
 msgid "read file names from stdin"
-msgstr "從標準輸入讀出檔案名"
+msgstr "從 stdin 讀出檔案名稱"
 
 #: builtin/check-attr.c builtin/check-ignore.c
 msgid "terminate input and output records by a NUL character"
-msgstr "輸入和輸出的紀錄使用 NUL 字元終結"
+msgstr "輸入和輸出的紀錄使用 NUL 字元終止"
+
+#: builtin/check-attr.c
+msgid "<tree-ish>"
+msgstr "<tree-ish>"
+
+#: builtin/check-attr.c
+msgid "which tree-ish to check attributes at"
+msgstr "要用哪一個樹狀物件檢查屬性"
 
 #: builtin/check-ignore.c builtin/checkout.c builtin/gc.c builtin/worktree.c
 msgid "suppress progress reporting"
@@ -4074,7 +4149,7 @@ msgstr "不顯示進度報告"
 
 #: builtin/check-ignore.c
 msgid "show non-matching input paths"
-msgstr "顯示符合的輸入路徑"
+msgstr "顯示符合的輸入路徑"
 
 #: builtin/check-ignore.c
 msgid "ignore index when checking"
@@ -4082,11 +4157,11 @@ msgstr "檢查時忽略索引"
 
 #: builtin/check-ignore.c
 msgid "cannot specify pathnames with --stdin"
-msgstr "不能同時指定路徑及 --stdin 參數"
+msgstr "無法同時指定路徑名稱及 --stdin"
 
 #: builtin/check-ignore.c
 msgid "-z only makes sense with --stdin"
-msgstr "-z é\9c\80è¦\81å\92\8c --stdin å\8f\83æ\95¸å\85±用才有意義"
+msgstr "-z é\9c\80è¦\81å\92\8c --stdin å\90\8cæ\99\82使用才有意義"
 
 #: builtin/check-ignore.c
 msgid "no path specified"
@@ -4094,11 +4169,11 @@ msgstr "未指定路徑"
 
 #: builtin/check-ignore.c
 msgid "--quiet is only valid with a single pathname"
-msgstr "å\8f\83æ\95¸ --quiet å\8fªå\9c¨æ\8f\90ä¾\9bä¸\80å\80\8bè·¯å¾\91å\90\8d時有效"
+msgstr "å¼\95æ\95¸ --quiet å\8fªå\9c¨æ\8f\90ä¾\9bä¸\80å\80\8bè·¯å¾\91å\90\8d稱時有效"
 
 #: builtin/check-ignore.c
 msgid "cannot have both --quiet and --verbose"
-msgstr "不能同時提供 --quiet 和 --verbose 參數"
+msgstr "無法同時傳入 --quiet 和 --verbose"
 
 #: builtin/check-ignore.c
 msgid "--non-matching is only valid with --verbose"
@@ -4106,41 +4181,41 @@ msgstr "--non-matching 選項只在使用 --verbose 時有效"
 
 #: builtin/check-mailmap.c
 msgid "git check-mailmap [<options>] <contact>..."
-msgstr "git check-mailmap [<選項>] <聯繫位址>..."
+msgstr "git check-mailmap [<options>] <contact>..."
 
 #: builtin/check-mailmap.c
 msgid "also read contacts from stdin"
-msgstr "還從標準輸入讀取聯繫位址"
+msgstr "亦從 stdin 讀取聯絡地址"
 
 #: builtin/check-mailmap.c
 #, c-format
 msgid "unable to parse contact: %s"
-msgstr "不能解析聯繫位址:%s"
+msgstr "無法解析聯絡地址:%s"
 
 #: builtin/check-mailmap.c
 msgid "no contacts specified"
-msgstr "æ\9cªæ\8c\87å®\9aè\81¯ç¹«ä½\8d址"
+msgstr "æ\9cªæ\8c\87å®\9aè\81¯çµ¡å\9c°址"
 
 #: builtin/checkout--worker.c
 msgid "git checkout--worker [<options>]"
-msgstr "git checkout--worker [<選項>]"
+msgstr "git checkout--worker [<options>]"
 
 #: builtin/checkout--worker.c builtin/checkout-index.c builtin/column.c
 #: builtin/submodule--helper.c builtin/worktree.c
 msgid "string"
-msgstr "字串"
+msgstr "string"
 
 #: builtin/checkout--worker.c builtin/checkout-index.c
 msgid "when creating files, prepend <string>"
-msgstr "å\9c¨å»ºç«\8bæª\94æ¡\88æ\99\82ï¼\8cå\9c¨å\89\8dé\9d¢å\8a ä¸\8a <å­\97串>"
+msgstr "建ç«\8bæª\94æ¡\88æ\99\82ï¼\8cå\9c¨å\89\8dé\9d¢å\8a ä¸\8a <string>"
 
 #: builtin/checkout-index.c
 msgid "git checkout-index [<options>] [--] [<file>...]"
-msgstr "git checkout-index [<選項>] [--] [<檔案>...]"
+msgstr "git checkout-index [<options>] [--] [<file>...]"
 
 #: builtin/checkout-index.c
 msgid "stage should be between 1 and 3 or all"
-msgstr "索引值應該取值 1 到 3 或者 all"
+msgstr "stage 應該是 1 到 3 的值,或者是 all"
 
 #: builtin/checkout-index.c
 msgid "check out all files in the index"
@@ -4164,11 +4239,11 @@ msgstr "不簽出新檔案"
 
 #: builtin/checkout-index.c
 msgid "update stat information in the index file"
-msgstr "更新索引檔案的狀態訊息"
+msgstr "更新索引檔案的狀態訊息"
 
 #: builtin/checkout-index.c
 msgid "read list of paths from the standard input"
-msgstr "從標準輸入讀取路徑列表"
+msgstr "從標準輸入讀取路徑清單"
 
 #: builtin/checkout-index.c
 msgid "write the content to temporary files"
@@ -4180,49 +4255,49 @@ msgstr "從指定暫存區中拷出檔案"
 
 #: builtin/checkout.c
 msgid "git checkout [<options>] <branch>"
-msgstr "git checkout [<選項>] <分支>"
+msgstr "git checkout [<options>] <branch>"
 
 #: builtin/checkout.c
 msgid "git checkout [<options>] [<branch>] -- <file>..."
-msgstr "git checkout [<選項>] [<分支>] -- <檔案>..."
+msgstr "git checkout [<options>] [<branch>] -- <file>..."
 
 #: builtin/checkout.c
 msgid "git switch [<options>] [<branch>]"
-msgstr "git switch [<選項>] [<分支>]"
+msgstr "git switch [<options>] [<branch>]"
 
 #: builtin/checkout.c
 msgid "git restore [<options>] [--source=<branch>] <file>..."
-msgstr "git restore [<選項>] [--source=<分支>] <檔案>..."
+msgstr "git restore [<options>] [--source=<branch>] <file>..."
 
 #: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have our version"
-msgstr "路徑 '%s' 沒有我們的版本"
+msgstr "“%s” 路徑沒有我們的版本"
 
 #: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have their version"
-msgstr "路徑 '%s' 沒有他們的版本"
+msgstr "“%s” 路徑沒有他們的版本"
 
 #: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have all necessary versions"
-msgstr "路徑 '%s' 沒有全部必需的版本"
+msgstr "“%s” 路徑沒有所有必須的版本"
 
 #: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have necessary versions"
-msgstr "路徑 '%s' 沒有必需的版本"
+msgstr "“%s” 路徑沒有必須的版本"
 
 #: builtin/checkout.c
 #, c-format
 msgid "path '%s': cannot merge"
-msgstr "path '%s':無法合併"
+msgstr "path “%s”:無法合併"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Unable to add merge result for '%s'"
-msgstr "無法為 '%s' 新增合併結果"
+msgstr "無法為 “%s” 加上合併結果"
 
 #: builtin/checkout.c
 #, c-format
@@ -4240,41 +4315,41 @@ msgstr[0] "從 %2$s 更新了 %1$d 個路徑"
 #, c-format
 msgid "Updated %d path from the index"
 msgid_plural "Updated %d paths from the index"
-msgstr[0] "å¾\9eç´¢å¼\95å\8d\80æ\9b´æ\96°äº\86 %d 個路徑"
+msgstr[0] "å·²å¾\9eç´¢å¼\95å\8d\80æ\9b´æ\96° %d 個路徑"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot be used with updating paths"
-msgstr "'%s' 不能在更新路徑時使用"
+msgstr "無法在更新路徑時使用 “%s”"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Cannot update paths and switch to branch '%s' at the same time."
-msgstr "不能同時更新路徑並切換到分支'%s'。"
+msgstr "無法同時更新路徑和切換至 “%s” 分支。"
 
 #: builtin/checkout.c
 #, c-format
 msgid "neither '%s' or '%s' is specified"
-msgstr "'%s' 或 '%s' 都沒有指定"
+msgstr "“%s” 或 “%s” 皆未指定"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' must be used when '%s' is not specified"
-msgstr "未指定 '%2$s' 時,必須使用 '%1$s'"
+msgstr "未指定 “%2$s” 時,必須使用 “%1$s”"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' or '%s' cannot be used with %s"
-msgstr "'%s' 或 '%s' 不能和 %s 一起使用"
+msgstr "“%s” 或 “%s” 無法與 %s 一起使用"
 
 #: builtin/checkout.c
 #, c-format
 msgid "path '%s' is unmerged"
-msgstr "路徑 '%s' 未合併"
+msgstr "路徑 “%s” 未合併"
 
 #: builtin/checkout.c
 msgid "you need to resolve your current index first"
-msgstr "您需要先解決目前索引的衝突"
+msgstr "您需要先解決目前索引的衝突"
 
 #: builtin/checkout.c
 #, c-format
@@ -4282,13 +4357,13 @@ msgid ""
 "cannot continue with staged changes in the following files:\n"
 "%s"
 msgstr ""
-"不能繼續,下列檔案有暫存的修改:\n"
+"無法繼續,下列檔案有暫存的更動:\n"
 "%s"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Can not do reflog for '%s': %s\n"
-msgstr "不能對 '%s' 執行 reflog 動作:%s\n"
+msgstr "無法對 “%s” 執行 reflog 動作:%s\n"
 
 #: builtin/checkout.c
 msgid "HEAD is now at"
@@ -4296,38 +4371,38 @@ msgstr "HEAD 目前位於"
 
 #: builtin/checkout.c builtin/clone.c t/helper/test-fast-rebase.c
 msgid "unable to update HEAD"
-msgstr "不能更新 HEAD"
+msgstr "無法更新 HEAD"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Reset branch '%s'\n"
-msgstr "重設分支 '%s'\n"
+msgstr "重設分支 “%s”\n"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Already on '%s'\n"
-msgstr "已經位於 '%s'\n"
+msgstr "已經位於 “%s”\n"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
-msgstr "å\88\87æ\8f\9b並é\87\8d設å\88\86æ\94¯ '%s'\n"
+msgstr "å·²å\88\87æ\8f\9b並é\87\8d設å\88\86æ\94¯ â\80\9c%sâ\80\9d\n"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Switched to a new branch '%s'\n"
-msgstr "å\88\87æ\8f\9bå\88°ä¸\80å\80\8bæ\96°å\88\86æ\94¯ '%s'\n"
+msgstr "å·²å\88\87æ\8f\9bè\87³æ\96°å\88\86æ\94¯ â\80\9c%sâ\80\9d\n"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Switched to branch '%s'\n"
-msgstr "å\88\87æ\8f\9bå\88°å\88\86æ\94¯ '%s'\n"
+msgstr "å·²å\88\87æ\8f\9bè\87³å\88\86æ\94¯ â\80\9c%sâ\80\9d\n"
 
 #  譯者:請維持前導空格
 #: builtin/checkout.c
 #, c-format
 msgid " ... and %d more.\n"
-msgstr " ... 及其它 %d 個。\n"
+msgstr " …… 及其它 %d 個。\n"
 
 #: builtin/checkout.c
 #, c-format
@@ -4342,7 +4417,8 @@ msgid_plural ""
 "\n"
 "%s\n"
 msgstr[0] ""
-"警告:您正丟下 %d 個提交,未和任何分支關聯:\n"
+"警告:您正丟下 %d 個\n"
+"未和任何分支關聯的提交:\n"
 "\n"
 "%s\n"
 
@@ -4361,23 +4437,23 @@ msgid_plural ""
 " git branch <new-branch-name> %s\n"
 "\n"
 msgstr[0] ""
-"如果您想要透過建立新分支儲存它,這可能是一個好時候。\n"
-"如下動作:\n"
+"如果您想要透過建立新分支留下這些提交,\n"
+"現在很適合執行:\n"
 "\n"
-" git branch <新分支名> %s\n"
+" git branch <新分支名> %s\n"
 "\n"
 
 #: builtin/checkout.c
 msgid "internal error in revision walk"
-msgstr "在版本遍歷時遇到內部錯誤"
+msgstr "在修訂版遍歷時遇到內部錯誤"
 
 #: builtin/checkout.c
 msgid "Previous HEAD position was"
-msgstr "之前的 HEAD 位置是"
+msgstr "之前的 HEAD 指針位置在"
 
 #: builtin/checkout.c
 msgid "You are on a branch yet to be born"
-msgstr "您位於一個尚未初始化的分支"
+msgstr "您位於一個尚未初始化的分支"
 
 #: builtin/checkout.c
 #, c-format
@@ -4385,7 +4461,7 @@ msgid ""
 "'%s' could be both a local file and a tracking branch.\n"
 "Please use -- (and optionally --no-guess) to disambiguate"
 msgstr ""
-"'%s' 既可以是一個本機檔案,也可以是一個追蹤分支。\n"
+"“%s” 既可以是本機檔案,也可以是追蹤分支。\n"
 "請使用 --(和可選的 --no-guess)來消除歧義"
 
 #: builtin/checkout.c
@@ -4399,18 +4475,19 @@ msgid ""
 "one remote, e.g. the 'origin' remote, consider setting\n"
 "checkout.defaultRemote=origin in your config."
 msgstr ""
-"如果您想要簽出一個遠端追蹤分支,例如 'origin',您可以\n"
-"使用 --track 選項寫出全名:\n"
+"如果您想要簽出遠端追蹤分支,例如 “origin”,\n"
+"您可以使用 --track 選項寫出全名:\n"
 "\n"
 "    git checkout --track origin/<name>\n"
 "\n"
-"如果您總是喜歡使用模糊的簡短分支名 <name>,而不喜歡如 'origin' 的遠端\n"
-"版本庫名,可以在設定中設定 checkout.defaultRemote=origin。"
+"如果您平時比較想要使用模糊的簡短分支名稱 <name>,\n"
+"而不太想寫如 “origin” 的遠端版本庫名稱,\n"
+"可以在組態中設定 checkout.defaultRemote=origin。"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' matched multiple (%d) remote tracking branches"
-msgstr "'%s' 符合多個 (%d) 遠端追蹤分支"
+msgstr "“%s” 符合多個 (%d) 遠端追蹤分支"
 
 #: builtin/checkout.c
 msgid "only one reference expected"
@@ -4419,7 +4496,7 @@ msgstr "預期只有一個引用"
 #: builtin/checkout.c
 #, c-format
 msgid "only one reference expected, %d given."
-msgstr "只有一個引用,卻提供了 %d 個。"
+msgstr "預期只有一個引用,卻提供了 %d 個。"
 
 #: builtin/checkout.c builtin/worktree.c
 #, c-format
@@ -4429,112 +4506,112 @@ msgstr "無效引用:%s"
 #: builtin/checkout.c
 #, c-format
 msgid "reference is not a tree: %s"
-msgstr "引用不是一個樹:%s"
+msgstr "引用不是樹狀物件:%s"
 
 #: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got tag '%s'"
-msgstr "期望一個分支,得到標籤 '%s'"
+msgstr "預期收到分支,卻收到標籤 “%s”"
 
 #: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got remote branch '%s'"
-msgstr "期望一個分支,得到遠端分支 '%s'"
+msgstr "預期收到分支,卻收到遠端分支 “%s”"
 
 #: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got '%s'"
-msgstr "期望一個分支,得到 '%s'"
+msgstr "預期收到分支,卻收到 “%s”"
 
 #: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got commit '%s'"
-msgstr "期望一個分支,得到提交 '%s'"
+msgstr "預期收到分支,卻收到提交 “%s”"
 
 #: builtin/checkout.c
 msgid ""
 "If you want to detach HEAD at the commit, try again with the --detach option."
-msgstr "è\8b¥æ\82¨æ\83³è¦\81å\88\86é\9b¢æ\8f\90交ç\9a\84 HEAD,請傳入 --detach 選項重試。"
+msgstr "è\8b¥æ\82¨æ\83³è¦\81å\9c¨æ­¤æ\8f\90交å\88\86é\9b¢ HEAD æ\8c\87é\87\9d,請傳入 --detach 選項重試。"
 
 #: builtin/checkout.c
 msgid ""
 "cannot switch branch while merging\n"
 "Consider \"git merge --quit\" or \"git worktree add\"."
 msgstr ""
-"不能在合併時切換分支\n"
-"è\80\83æ\85®ä½¿ç\94¨ \"git merge --quit\" æ\88\96 \"git worktree add\"。"
+"無法在合併時切換分支\n"
+"è«\8b試試 â\80\9cgit merge --quitâ\80\9d æ\88\96 â\80\9cgit worktree addâ\80\9d。"
 
 #: builtin/checkout.c
 msgid ""
 "cannot switch branch in the middle of an am session\n"
 "Consider \"git am --quit\" or \"git worktree add\"."
 msgstr ""
-"不能在 am 工作階段期間切換分支\n"
-"è\80\83æ\85®ä½¿ç\94¨ \"git am --quit\" æ\88\96 \"git worktree add\"。"
+"無法在 am 工作階段期間時切換分支\n"
+"è«\8b試試 â\80\9cgit am --quitâ\80\9d æ\88\96 â\80\9cgit worktree addâ\80\9d。"
 
 #: builtin/checkout.c
 msgid ""
 "cannot switch branch while rebasing\n"
 "Consider \"git rebase --quit\" or \"git worktree add\"."
 msgstr ""
-"不能在重定基底時切換分支\n"
-"è\80\83æ\85®ä½¿ç\94¨ \"git rebase --quit\" æ\88\96 \"git worktree add\"。"
+"無法在重定基底時切換分支\n"
+"è«\8b試試 â\80\9cgit rebase --quitâ\80\9d æ\88\96 â\80\9cgit worktree addâ\80\9d。"
 
 #: builtin/checkout.c
 msgid ""
 "cannot switch branch while cherry-picking\n"
 "Consider \"git cherry-pick --quit\" or \"git worktree add\"."
 msgstr ""
-"不能在揀選時切換分支\n"
-"è\80\83æ\85®ä½¿ç\94¨ \"git cherry-pick --quit\" æ\88\96 \"git worktree add\"。"
+"無法在揀選時切換分支\n"
+"è«\8b試試 â\80\9cgit cherry-pick --quitâ\80\9d æ\88\96 â\80\9cgit worktree addâ\80\9d。"
 
 #: builtin/checkout.c
 msgid ""
 "cannot switch branch while reverting\n"
 "Consider \"git revert --quit\" or \"git worktree add\"."
 msgstr ""
-"不能在還原時切換分支\n"
-"è\80\83æ\85®ä½¿ç\94¨ \"git revert --quit\" æ\88\96 \"git worktree add\"。"
+"無法在還原時切換分支\n"
+"è«\8b試試 â\80\9cgit revert --quitâ\80\9d æ\88\96 â\80\9cgit worktree addâ\80\9d。"
 
 #: builtin/checkout.c
 msgid "you are switching branch while bisecting"
-msgstr "您在行二分搜尋時切換分支"
+msgstr "您在行二分搜尋時切換分支"
 
 #: builtin/checkout.c
 msgid "paths cannot be used with switching branches"
-msgstr "路徑不能切換分支同時使用"
+msgstr "路徑不能切換分支同時使用"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot be used with switching branches"
-msgstr "'%s' 不能和切換分支同時使用"
+msgstr "“%s” 不能與切換分支同時使用"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot be used with '%s'"
-msgstr "'%s' 不能和 '%s' 同時使用"
+msgstr "“%s” 不能與 “%s” 同時使用"
 
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot take <start-point>"
-msgstr "'%s' 不帶 <起始點>"
+msgstr "“%s” 不取 <start-point>"
 
 #: builtin/checkout.c
 #, c-format
 msgid "Cannot switch branch to a non-commit '%s'"
-msgstr "不能切換分支到一個非提交 '%s'"
+msgstr "無法將分支切換至非提交項目 “%s”"
 
 #: builtin/checkout.c
 msgid "missing branch or commit argument"
-msgstr "缺å°\91å\88\86æ\94¯æ\88\96æ\8f\90交å\8f\83數"
+msgstr "缺å°\91å\88\86æ\94¯æ\88\96æ\8f\90交å¼\95數"
 
 #: builtin/checkout.c
 msgid "perform a 3-way merge with the new branch"
-msgstr "和新的分支執行三方合併"
+msgstr "和新分支進行三方合併"
 
 #: builtin/checkout.c builtin/log.c parse-options.h
 msgid "style"
-msgstr "風格"
+msgstr "style"
 
 #: builtin/checkout.c
 msgid "conflict style (merge, diff3, or zdiff3)"
@@ -4542,7 +4619,7 @@ msgstr "衝突輸出風格(merge、diff3 或 zdiff3)"
 
 #: builtin/checkout.c builtin/worktree.c
 msgid "detach HEAD at named commit"
-msgstr "HEAD 從指定的提交分離"
+msgstr "自指定提交分離 HEAD 指針"
 
 #: builtin/checkout.c
 msgid "force checkout (throw away local modifications)"
@@ -4550,19 +4627,19 @@ msgstr "強制簽出(捨棄本機修改)"
 
 #: builtin/checkout.c
 msgid "new-branch"
-msgstr "新分支"
+msgstr "new-branch"
 
 #: builtin/checkout.c
 msgid "new unparented branch"
-msgstr "新的沒有父提交的分支"
+msgstr "新的沒有父提交的分支"
 
 #: builtin/checkout.c builtin/merge.c
 msgid "update ignored files (default)"
-msgstr "更新忽略的檔案(預設)"
+msgstr "更新忽略的檔案(預設)"
 
 #: builtin/checkout.c
 msgid "do not check if another worktree is holding the given ref"
-msgstr "不檢查指定的引用是否被其他工作區所占用"
+msgstr "不檢查其他工作區是否正在佔用指定的引用"
 
 #: builtin/checkout.c
 msgid "checkout our version for unmerged files"
@@ -4574,16 +4651,16 @@ msgstr "對尚未合併的檔案簽出他們的版本"
 
 #: builtin/checkout.c
 msgid "do not limit pathspecs to sparse entries only"
-msgstr "對路徑不做稀疏簽出的限制"
+msgstr "對路徑規格不做稀疏簽出的限制"
 
 #: builtin/checkout.c
 #, c-format
 msgid "options '-%c', '-%c', and '%s' cannot be used together"
-msgstr "「-%c」、「-%c」和「%s」選項不得同時使用"
+msgstr "“-%c”、“-%c” 和 “%s” 選項不得同時使用"
 
 #: builtin/checkout.c
 msgid "--track needs a branch name"
-msgstr "--track 需要一個分支名"
+msgstr "--track 需要分支名稱"
 
 #: builtin/checkout.c
 #, c-format
@@ -4602,60 +4679,61 @@ msgstr "無效的路徑規格"
 #: builtin/checkout.c
 #, c-format
 msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
-msgstr "'%s' 不是一個提交,不能基於它建立分支 '%s'"
+msgstr "“%s” 不是提交,因此不能以這為基礎建立 “%s” 分支"
 
 #: builtin/checkout.c
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
-msgstr "git checkout:--detach 不能接收路徑參數 '%s'"
+msgstr "git checkout:--detach 不取路徑引數 “%s”"
 
 #: builtin/checkout.c
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
 msgstr ""
-"git checkout:在從索引簽出時,--ours/--theirs、--force 和 --merge 不相容。"
+"git checkout:在從索引簽出時,--ours/--theirs、--force\n"
+"和 --merge 不相容。"
 
 #: builtin/checkout.c
 msgid "you must specify path(s) to restore"
-msgstr "您必須指定一個要復原的路徑"
+msgstr "您必須指定要還原的路徑"
 
 #: builtin/checkout.c builtin/clone.c builtin/remote.c
 #: builtin/submodule--helper.c builtin/worktree.c
 msgid "branch"
-msgstr "分支"
+msgstr "branch"
 
 #: builtin/checkout.c
 msgid "create and checkout a new branch"
-msgstr "建立並簽出一個新的分支"
+msgstr "建立並簽出分支"
 
 #: builtin/checkout.c
 msgid "create/reset and checkout a branch"
-msgstr "建立/重設並簽出一個分支"
+msgstr "建立/重設並簽出分支"
 
 #: builtin/checkout.c
 msgid "create reflog for new branch"
-msgstr "為新分支建立引用日誌"
+msgstr "為新分支建立引用日誌"
 
 #: builtin/checkout.c
 msgid "second guess 'git checkout <no-such-branch>' (default)"
-msgstr "二次猜測 'git checkout <無此分支>'(預設)"
+msgstr "二次猜測 “git checkout <無此分支>”(預設值)"
 
 #: builtin/checkout.c
 msgid "use overlay mode (default)"
-msgstr "使用疊加模式(預設)"
+msgstr "使用疊加模式(預設)"
 
 #: builtin/checkout.c
 msgid "create and switch to a new branch"
-msgstr "建立並切換一個新分支"
+msgstr "建立並切換新分支"
 
 #: builtin/checkout.c
 msgid "create/reset and switch to a branch"
-msgstr "建立/重設並切換一個分支"
+msgstr "建立/重設並切換至指定分支"
 
 #: builtin/checkout.c
 msgid "second guess 'git switch <no-such-branch>'"
-msgstr "二次猜測 'git switch <無此分支>'"
+msgstr "二次猜測 “git switch <無此分支>”"
 
 #: builtin/checkout.c
 msgid "throw away local modifications"
@@ -4663,19 +4741,19 @@ msgstr "捨棄本機修改"
 
 #: builtin/checkout.c
 msgid "which tree-ish to checkout from"
-msgstr "要簽出哪一個樹"
+msgstr "要自哪一個樹狀物件指示元簽出"
 
 #: builtin/checkout.c
 msgid "restore the index"
-msgstr "原索引"
+msgstr "原索引"
 
 #: builtin/checkout.c
 msgid "restore the working tree (default)"
-msgstr "復原工作區(預設)"
+msgstr "還原工作區(預設值)"
 
 #: builtin/checkout.c
 msgid "ignore unmerged entries"
-msgstr "忽略未合併目"
+msgstr "忽略未合併目"
 
 #: builtin/checkout.c
 msgid "use overlay mode"
@@ -4686,17 +4764,18 @@ msgid ""
 "git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] "
 "[<pathspec>...]"
 msgstr ""
-"git clean [-d] [-f] [-i] [-n] [-q] [-e <模式>] [-x | -X] [--] [<路徑規格>...]"
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] "
+"[<pathspec>...]"
 
 #: builtin/clean.c
 #, c-format
 msgid "Removing %s\n"
-msgstr "正刪除 %s\n"
+msgstr "æ­£å\9c¨å\88ªé\99¤ %s\n"
 
 #: builtin/clean.c
 #, c-format
 msgid "Would remove %s\n"
-msgstr "將刪除 %s\n"
+msgstr "將刪除 %s\n"
 
 #: builtin/clean.c
 #, c-format
@@ -4711,12 +4790,12 @@ msgstr "將忽略版本庫 %s\n"
 #: builtin/clean.c midx.c
 #, c-format
 msgid "failed to remove %s"
-msgstr "刪除 %s 失敗"
+msgstr "無法移除 %s"
 
 #: builtin/clean.c
 #, c-format
 msgid "could not lstat %s\n"
-msgstr "不能對 %s 呼叫 lstat\n"
+msgstr "不能對 %s 進行 lstat\n"
 
 #: builtin/clean.c
 msgid "Refusing to remove current working directory\n"
@@ -4726,7 +4805,7 @@ msgstr "拒絕移除目前工作目錄\n"
 msgid "Would refuse to remove current working directory\n"
 msgstr "會拒絕移除目前的工作目錄\n"
 
-#: builtin/clean.c git-add--interactive.perl
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4734,12 +4813,12 @@ msgid ""
 "foo        - select item based on unique prefix\n"
 "           - (empty) select nothing\n"
 msgstr ""
-"協助:\n"
-"1          - 透過編號選擇一個選項\n"
-"foo        - 透過唯一前綴選擇一個選項\n"
+"提示說明:\n"
+"1          - 透過編號選擇項目\n"
+"foo        - 根據獨特前綴選擇項目\n"
 "           - (空)什麼也不選擇\n"
 
-#: builtin/clean.c git-add--interactive.perl
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4751,39 +4830,39 @@ msgid ""
 "*          - choose all items\n"
 "           - (empty) finish selecting\n"
 msgstr ""
-"協助:\n"
-"1          - é\81¸æ\93\87ä¸\80å\80\8bé\81¸é \85\n"
-"3-5        - 選擇一個範圍內的所有選項\n"
-"2-3,6-9    - 選擇多個範圍內的所有選項\n"
-"foo        - 透過唯一前綴選擇一個選項\n"
-"-...       - å\8f\8dé\81¸ç\89¹å®\9aç\9a\84é\81¸é \85\n"
-"*          - é\81¸æ\93\87æ\89\80æ\9c\89é\81¸é \85\n"
-"           - (空)結束選擇\n"
-
-#: builtin/clean.c git-add--interactive.perl
-#, c-format, perl-format
+"提示說明:\n"
+"1          - é\81¸æ\93\87ä¸\80å\80\8bé \85ç\9b®\n"
+"3-5        - 選擇一個項目範圍\n"
+"2-3,6-9    - 選擇多個項目範圍\n"
+"foo        - 根據獨特前綴選擇項目\n"
+"-...       - å\8f\96æ¶\88é\81¸å\8f\96æ\8c\87å®\9aé \85ç\9b®\n"
+"*          - é\81¸æ\93\87æ\89\80æ\9c\89é \85ç\9b®\n"
+"           - (空)完成選擇\n"
+
+#: builtin/clean.c
+#, c-format
 msgid "Huh (%s)?\n"
-msgstr "嗯(%s)\n"
+msgstr "嗯(%s)?\n"
 
 #: builtin/clean.c
 #, c-format
 msgid "Input ignore patterns>> "
-msgstr "輸入範本以排除條目>> "
+msgstr "輸入要忽略的模式項目>> "
 
 #: builtin/clean.c
 #, c-format
 msgid "WARNING: Cannot find items matched by: %s"
-msgstr "警告:無法找到和 %s 符合的目"
+msgstr "警告:無法找到和 %s 符合的目"
 
 #: builtin/clean.c
 msgid "Select items to delete"
-msgstr "選擇要刪除的目"
+msgstr "選擇要刪除的目"
 
 #. TRANSLATORS: Make sure to keep [y/N] as is
 #: builtin/clean.c
 #, c-format
 msgid "Remove %s [y/N]? "
-msgstr "移除 %s [y/N] "
+msgstr "移除 %s [y/N]? "
 
 #: builtin/clean.c
 msgid ""
@@ -4798,15 +4877,15 @@ msgstr ""
 "clean               - 開始清理\n"
 "filter by pattern   - 透過範本排除要刪除的條目\n"
 "select by numbers   - 透過數字選擇要刪除的條目\n"
-"ask each            - 針對刪除逐一詢問(就像 \"rm -i\")\n"
+"ask each            - 針對刪除逐一詢問(就像 “rm -i”)\n"
 "quit                - 停止刪除並離開\n"
-"help                - 顯示本協助\n"
-"?                   - 顯示如何在提示下選擇的協助"
+"help                - 顯示本輔助說明\n"
+"?                   - 顯示如何在提示下選擇的協助"
 
 #: builtin/clean.c
 msgid "Would remove the following item:"
 msgid_plural "Would remove the following items:"
-msgstr[0] "將刪除如下條目:"
+msgstr[0] "將移除以下項目:"
 
 #: builtin/clean.c
 msgid "No more files to clean, exiting."
@@ -4814,11 +4893,11 @@ msgstr "沒有要清理的檔案,離開。"
 
 #: builtin/clean.c
 msgid "do not print names of files removed"
-msgstr "不列印刪除檔案的名稱"
+msgstr "不輸出移除的檔案的名稱"
 
 #: builtin/clean.c
 msgid "force"
-msgstr "強制"
+msgstr "force"
 
 #: builtin/clean.c
 msgid "interactive cleaning"
@@ -4826,24 +4905,25 @@ msgstr "互動式清除"
 
 #: builtin/clean.c
 msgid "remove whole directories"
-msgstr "除整個目錄"
+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 "模式"
+msgstr "pattern"
 
 #: builtin/clean.c
 msgid "add <pattern> to ignore rules"
-msgstr "新增 <模式> 到忽略規則"
+msgstr "將 <pattern> 加到忽略規則"
 
 #: builtin/clean.c
 msgid "remove ignored files, too"
-msgstr "ä¹\9få\88ª除忽略的檔案"
+msgstr "亦移除忽略的檔案"
 
 #: builtin/clean.c
 msgid "remove only ignored files"
-msgstr "只除忽略的檔案"
+msgstr "只除忽略的檔案"
 
 #: builtin/clean.c
 msgid ""
@@ -4865,23 +4945,23 @@ msgstr "-x 和 -X 不能同時使用"
 
 #: builtin/clone.c
 msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<選項>] [--] <版本庫> [<路徑>]"
+msgstr "git clone [<options>] [--] <repo> [<dir>]"
 
 #: builtin/clone.c
 msgid "don't clone shallow repository"
-msgstr "不要複製淺版本庫"
+msgstr "不要複製淺版本庫"
 
 #: builtin/clone.c
 msgid "don't create a checkout"
-msgstr "不建ç«\8bä¸\80å\80\8bç°½å\87º"
+msgstr "不è¦\81建ç«\8bç°½å\87º"
 
 #: builtin/clone.c builtin/init-db.c
 msgid "create a bare repository"
-msgstr "建立一個純版本庫"
+msgstr "建立版本庫"
 
 #: builtin/clone.c
 msgid "create a mirror repository (implies bare)"
-msgstr "建立一個鏡像版本庫(也是純版本庫)"
+msgstr "建立鏡像版本庫(亦即裸版本庫)"
 
 #: builtin/clone.c
 msgid "to clone from a local repository"
@@ -4889,7 +4969,7 @@ msgstr "從本機版本庫複製"
 
 #: builtin/clone.c
 msgid "don't use local hardlinks, always copy"
-msgstr "不使用本機硬連結,始終複製"
+msgstr "不使用本機硬連結,始終拷貝"
 
 #: builtin/clone.c
 msgid "setup as shared repository"
@@ -4905,15 +4985,15 @@ msgstr "在複製時初始化子模組"
 
 #: builtin/clone.c
 msgid "number of submodules cloned in parallel"
-msgstr "並行複製的子模組數"
+msgstr "平行複製的子模組數量"
 
 #: builtin/clone.c builtin/init-db.c
 msgid "template-directory"
-msgstr "範本目錄"
+msgstr "模板目錄"
 
 #: builtin/clone.c builtin/init-db.c
 msgid "directory from which templates will be used"
-msgstr "範本目錄將被使用"
+msgstr "將被使用的模板目錄"
 
 #: builtin/clone.c builtin/submodule--helper.c
 msgid "reference repository"
@@ -4921,21 +5001,21 @@ msgstr "引用版本庫"
 
 #: builtin/clone.c builtin/submodule--helper.c
 msgid "use --reference only while cloning"
-msgstr "僅在複製時參考 --reference 指向的本機版本庫"
+msgstr "僅在複製時使用 --reference"
 
 #: builtin/clone.c builtin/column.c builtin/fmt-merge-msg.c builtin/init-db.c
 #: builtin/merge-file.c builtin/merge.c builtin/pack-objects.c builtin/repack.c
 #: builtin/submodule--helper.c t/helper/test-simple-ipc.c
 msgid "name"
-msgstr "名稱"
+msgstr "name"
 
 #: builtin/clone.c
 msgid "use <name> instead of 'origin' to track upstream"
-msgstr "使用 <名稱> 而不是 'origin' 去追蹤上游"
+msgstr "使用 <name> 而不是 “origin” 追蹤上游"
 
 #: builtin/clone.c
 msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "簽出 <分支> 而不是遠端 HEAD"
+msgstr "簽出 <branch> 而不是遠端 HEAD"
 
 #: builtin/clone.c
 msgid "path to git-upload-pack on the remote"
@@ -4943,27 +5023,23 @@ msgstr "遠端 git-upload-pack 路徑"
 
 #: builtin/clone.c builtin/fetch.c builtin/grep.c builtin/pull.c
 msgid "depth"
-msgstr "深度"
+msgstr "depth"
 
 #: builtin/clone.c
 msgid "create a shallow clone of that depth"
-msgstr "建立一個指定深度的淺複製"
-
-#: builtin/clone.c builtin/fetch.c builtin/pack-objects.c builtin/pull.c
-msgid "time"
-msgstr "時間"
+msgstr "建立指定深度的淺層複製"
 
 #: builtin/clone.c
 msgid "create a shallow clone since a specific time"
-msgstr "建立從指定時間到現在的淺複製"
+msgstr "建立從指定時間到現在的淺複製"
 
 #: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c
 msgid "revision"
-msgstr "修訂版"
+msgstr "revision"
 
 #: builtin/clone.c builtin/fetch.c builtin/pull.c
 msgid "deepen history of shallow clone, excluding rev"
-msgstr "取得更多淺複製的過去歷史記錄,除了特定版本"
+msgstr "取得更多淺層複製的過去歷史記錄,除了特定修訂版"
 
 #: builtin/clone.c builtin/submodule--helper.c
 msgid "clone only one branch, HEAD or --branch"
@@ -4979,11 +5055,11 @@ msgstr "子模組將以淺下載模式複製"
 
 #: builtin/clone.c builtin/init-db.c
 msgid "gitdir"
-msgstr "git目錄"
+msgstr "gitdir"
 
 #: builtin/clone.c builtin/init-db.c
 msgid "separate git dir from working tree"
-msgstr "git目錄和工作區分離"
+msgstr "git 目錄和工作區分離"
 
 #: builtin/clone.c
 msgid "key=value"
@@ -5003,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 "將部分複製過濾器套用至子模組"
@@ -5046,6 +5114,11 @@ msgstr "對 '%s' 呼叫 stat 失敗"
 msgid "%s exists and is not a directory"
 msgstr "%s 存在且不是一個目錄"
 
+#: builtin/clone.c
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "“%s” 是個符號連結,故不能使用 --local 複製"
+
 #: builtin/clone.c
 #, c-format
 msgid "failed to start iterator over '%s'"
@@ -5059,7 +5132,7 @@ msgstr "「%s」符號連結已存在,拒絕使用 --local 複製"
 #: builtin/clone.c compat/precompose_utf8.c
 #, c-format
 msgid "failed to unlink '%s'"
-msgstr "刪除 '%s' 失敗"
+msgstr "無法刪除 “%s”"
 
 #: builtin/clone.c
 #, c-format
@@ -5127,7 +5200,7 @@ msgstr "無法執行 repack 來清理"
 
 #: builtin/clone.c
 msgid "cannot unlink temporary alternates file"
-msgstr "無法刪除暫時的 alternates 檔案"
+msgstr "無法刪除暫 alternates 檔案"
 
 #: builtin/clone.c
 msgid "Too many arguments."
@@ -5240,6 +5313,10 @@ msgstr "無法初始化版本庫,略過套件包 URI"
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "無法從套件包 URL “%s” 抓取物件"
 
+#: builtin/clone.c
+msgid "failed to fetch advertised bundles"
+msgstr "無法抓取公佈的套件包"
+
 #: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "遠端傳輸回報錯誤"
@@ -5536,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 樹狀物件失敗"
@@ -5609,10 +5690,10 @@ msgid ""
 "in the current commit message"
 msgstr "無法選擇一個未被目前提交說明使用的備註字元"
 
-#: builtin/commit.c
+#: 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
@@ -5834,13 +5915,13 @@ msgstr "計算完整的領先/落後值"
 msgid "version"
 msgstr "版本"
 
-#: builtin/commit.c builtin/push.c builtin/worktree.c
+#: builtin/commit.c builtin/fetch.c builtin/push.c builtin/worktree.c
 msgid "machine-readable output"
 msgstr "機器可讀的輸出"
 
 #: builtin/commit.c
 msgid "show status in long format (default)"
-msgstr "以長格式顯示狀態(預設)"
+msgstr "以長格式顯示狀態(預設)"
 
 #: builtin/commit.c
 msgid "terminate entries with NUL"
@@ -5917,7 +5998,7 @@ msgstr "日期"
 msgid "override date for commit"
 msgstr "提交時覆蓋日期"
 
-#: builtin/commit.c parse-options.h ref-filter.h
+#: builtin/commit.c builtin/merge-tree.c parse-options.h ref-filter.h
 msgid "commit"
 msgstr "提交"
 
@@ -6068,7 +6149,7 @@ msgstr ""
 msgid "git config [<options>]"
 msgstr "git config [<選項>]"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 #, c-format
 msgid "unrecognized --type argument, %s"
 msgstr "無法識別的 --type 參數,%s"
@@ -6167,7 +6248,7 @@ msgstr "開啟一個編輯器"
 
 #: builtin/config.c
 msgid "find the color configured: slot [default]"
-msgstr "獲得設定的顏色:設定 [預設]"
+msgstr "獲得設定的顏色:設定 [預設]"
 
 #: builtin/config.c
 msgid "find the color setting: slot [stdout-is-tty]"
@@ -6177,11 +6258,11 @@ msgstr "獲得顏色設定:設定 [stdout-is-tty]"
 msgid "Type"
 msgstr "類型"
 
-#: builtin/config.c builtin/env--helper.c builtin/hash-object.c
+#: builtin/config.c builtin/hash-object.c
 msgid "type"
 msgstr "類型"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 msgid "value is given this type"
 msgstr "取值為該類型"
 
@@ -6235,7 +6316,7 @@ msgstr ""
 "顯示設定檔的作用域 (工作區 worktree、本機 local、全域 global、系統 system、指"
 "令 command)"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 msgid "value"
 msgstr "取值"
 
@@ -6770,30 +6851,6 @@ msgstr "沒有為 --tool=<工具> 參數提供 <工具>"
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "沒有為 --extcmd=<命令> 參數提供 <命令>"
 
-#: builtin/env--helper.c
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <選項> <環境變數>"
-
-#: builtin/env--helper.c
-msgid "default for git_env_*(...) to fall back on"
-msgstr "git_env_*(...) 的預設值"
-
-#: builtin/env--helper.c
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "安靜模式,只使用 git_env_*() 的值作為離開碼"
-
-#: builtin/env--helper.c
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr "選項「--default」預期收到「--type=bool」的布林值,而非「%s」"
-
-#: builtin/env--helper.c
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr "選項「--default」預期收到「--type=ulong」的無號 long 數值,而非「%s」"
-
 #: builtin/fast-export.c
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<rev-list-opts>]"
@@ -6936,145 +6993,15 @@ msgstr "git fetch --all [<選項>]"
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel 不能為負數"
 
-#: builtin/fetch.c builtin/pull.c
-msgid "fetch from all remotes"
-msgstr "從所有的遠端抓取"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "set upstream for git pull/fetch"
-msgstr "為 git pull/fetch 設定上游"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "追加到 .git/FETCH_HEAD 而不是覆蓋它"
-
-#: builtin/fetch.c
-msgid "use atomic transaction to update references"
-msgstr "使用 atomic 事務更新引用"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "path to upload pack on remote end"
-msgstr "上傳包到遠端的路徑"
-
-#: builtin/fetch.c
-msgid "force overwrite of local reference"
-msgstr "強制覆蓋本機引用"
-
-#: builtin/fetch.c
-msgid "fetch from multiple remotes"
-msgstr "從多個遠端抓取"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "fetch all tags and associated objects"
-msgstr "抓取所有的標籤和關聯物件"
-
-#: builtin/fetch.c
-msgid "do not fetch all tags (--no-tags)"
-msgstr "不抓取任何標籤(--no-tags)"
-
-#: builtin/fetch.c
-msgid "number of submodules fetched in parallel"
-msgstr "並行取得的子模組數量"
-
-#: builtin/fetch.c
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr "修改引用規格 (refspec) 以便將所有引用 (refs) 放置在 refs/prefetch/ 中"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "prune remote-tracking branches no longer on remote"
-msgstr "清除遠端已經不存在的分支的追蹤分支"
-
-#: builtin/fetch.c
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr "清除遠端不存在的本機標籤,並且取代變更標籤"
-
-#  譯者:可選值,不能翻譯
-#: builtin/fetch.c builtin/pull.c
-msgid "on-demand"
-msgstr "on-demand"
-
-#: builtin/fetch.c
-msgid "control recursive fetching of submodules"
-msgstr "控制子模組的遞迴抓取"
-
-#: builtin/fetch.c
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "將取得的引用寫入 FETCH_HEAD 檔案"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "keep downloaded pack"
-msgstr "保持下載包"
-
-#: builtin/fetch.c
-msgid "allow updating of HEAD ref"
-msgstr "允許更新 HEAD 引用"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow clone"
-msgstr "取得淺複製的更多過去歷史記錄"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow repository based on time"
-msgstr "基於時間來深化淺複製的歷史"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "convert to a complete repository"
-msgstr "轉換為一個完整的版本庫"
-
-#: builtin/fetch.c
-msgid "re-fetch without negotiating common commits"
-msgstr "重新抓取而不協商共同提交"
-
-#: builtin/fetch.c
-msgid "prepend this to submodule path output"
-msgstr "在子模組路徑輸出的前面加上此目錄"
-
-#: builtin/fetch.c
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr "遞迴取得子模組的預設值(比設定檔案優先度低)"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "accept refs that update .git/shallow"
-msgstr "接受更新 .git/shallow 的引用"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "refmap"
-msgstr "引用映射"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "specify fetch refmap"
-msgstr "指定取得動作的引用映射"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "report that we have only objects reachable from this object"
-msgstr "報告我們只擁有從該物件開始可以取得的物件"
-
-#: builtin/fetch.c
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr "不取得 packfile,而是輸出協商的祖先提交"
-
-#: builtin/fetch.c
-msgid "run 'maintenance --auto' after fetching"
-msgstr "取得 (fetch) 後執行 'maintenance --auto'"
-
-#: builtin/fetch.c builtin/pull.c
-msgid "check for forced-updates on all updated branches"
-msgstr "在所有更新分支上檢查強制更新"
-
-#: builtin/fetch.c
-msgid "write the commit-graph after fetching"
-msgstr "抓取後寫入分支圖"
-
-#: builtin/fetch.c
-msgid "accept refspecs from stdin"
-msgstr "從標準輸入中接受引用規格"
-
 #: builtin/fetch.c
 msgid "couldn't find remote ref HEAD"
 msgstr "找不到遠端 HEAD 引用"
 
+#: builtin/fetch.c
+#, c-format
+msgid "From %.*s\n"
+msgstr "來自 %.*s\n"
+
 #: builtin/fetch.c
 #, c-format
 msgid "object %s not found"
@@ -7160,11 +7087,6 @@ msgstr "%s 未傳送所有必需的物件\n"
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr "已拒絕 %s,不允許更新淺複製"
 
-#: builtin/fetch.c
-#, c-format
-msgid "From %.*s\n"
-msgstr "來自 %.*s\n"
-
 #: builtin/fetch.c
 #, c-format
 msgid ""
@@ -7278,6 +7200,141 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "您需要指定標籤名稱"
 
+#: builtin/fetch.c builtin/pull.c
+msgid "fetch from all remotes"
+msgstr "從所有的遠端抓取"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "set upstream for git pull/fetch"
+msgstr "為 git pull/fetch 設定上游"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "追加到 .git/FETCH_HEAD 而不是覆蓋它"
+
+#: builtin/fetch.c
+msgid "use atomic transaction to update references"
+msgstr "使用 atomic 事務更新引用"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "path to upload pack on remote end"
+msgstr "上傳包到遠端的路徑"
+
+#: builtin/fetch.c
+msgid "force overwrite of local reference"
+msgstr "強制覆蓋本機引用"
+
+#: builtin/fetch.c
+msgid "fetch from multiple remotes"
+msgstr "從多個遠端抓取"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "fetch all tags and associated objects"
+msgstr "抓取所有的標籤和關聯物件"
+
+#: builtin/fetch.c
+msgid "do not fetch all tags (--no-tags)"
+msgstr "不抓取任何標籤(--no-tags)"
+
+#: builtin/fetch.c
+msgid "number of submodules fetched in parallel"
+msgstr "並行取得的子模組數量"
+
+#: builtin/fetch.c
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr "修改引用規格 (refspec) 以便將所有引用 (refs) 放置在 refs/prefetch/ 中"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "prune remote-tracking branches no longer on remote"
+msgstr "清除遠端已經不存在的分支的追蹤分支"
+
+#: builtin/fetch.c
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr "清除遠端不存在的本機標籤,並且取代變更標籤"
+
+#  譯者:可選值,不能翻譯
+#: builtin/fetch.c builtin/pull.c
+msgid "on-demand"
+msgstr "on-demand"
+
+#: builtin/fetch.c
+msgid "control recursive fetching of submodules"
+msgstr "控制子模組的遞迴抓取"
+
+#: builtin/fetch.c
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "將取得的引用寫入 FETCH_HEAD 檔案"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "keep downloaded pack"
+msgstr "保持下載包"
+
+#: builtin/fetch.c
+msgid "allow updating of HEAD ref"
+msgstr "允許更新 HEAD 引用"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow clone"
+msgstr "取得淺複製的更多過去歷史記錄"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow repository based on time"
+msgstr "基於時間來深化淺複製的歷史"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "convert to a complete repository"
+msgstr "轉換為一個完整的版本庫"
+
+#: builtin/fetch.c
+msgid "re-fetch without negotiating common commits"
+msgstr "重新抓取而不協商共同提交"
+
+#: builtin/fetch.c
+msgid "prepend this to submodule path output"
+msgstr "在子模組路徑輸出的前面加上此目錄"
+
+#: builtin/fetch.c
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr "遞迴取得子模組的預設值(比設定檔案優先度低)"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "accept refs that update .git/shallow"
+msgstr "接受更新 .git/shallow 的引用"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "refmap"
+msgstr "引用映射"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "specify fetch refmap"
+msgstr "指定取得動作的引用映射"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "report that we have only objects reachable from this object"
+msgstr "報告我們只擁有從該物件開始可以取得的物件"
+
+#: builtin/fetch.c
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr "不取得 packfile,而是輸出協商的祖先提交"
+
+#: builtin/fetch.c
+msgid "run 'maintenance --auto' after fetching"
+msgstr "取得 (fetch) 後執行 'maintenance --auto'"
+
+#: builtin/fetch.c builtin/pull.c
+msgid "check for forced-updates on all updated branches"
+msgstr "在所有更新分支上檢查強制更新"
+
+#: builtin/fetch.c
+msgid "write the commit-graph after fetching"
+msgstr "抓取後寫入分支圖"
+
+#: builtin/fetch.c
+msgid "accept refspecs from stdin"
+msgstr "從標準輸入中接受引用規格"
+
 #: builtin/fetch.c
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only 需要一或多個 --negotiation-tip=*"
@@ -7290,6 +7347,11 @@ msgstr "--deepen 不支援負數深度"
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "對於一個完整的版本庫,參數 --unshallow 沒有意義"
 
+#: builtin/fetch.c
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "無法自「%s」抓取套件包"
+
 #: builtin/fetch.c
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all 不能帶一個版本庫參數"
@@ -7418,6 +7480,14 @@ msgstr "只列印包含該提交的引用"
 msgid "print only refs which don't contain the commit"
 msgstr "只列印不包含該提交的引用"
 
+#: builtin/for-each-ref.c
+msgid "read reference patterns from stdin"
+msgstr "從 stdin 讀取引用模式"
+
+#: builtin/for-each-ref.c
+msgid "unknown arguments supplied with --stdin"
+msgstr "為 --stdin 提供的引數未知"
+
 #: builtin/for-each-repo.c
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<config> [--] <arguments>"
@@ -7434,6 +7504,11 @@ msgstr "儲存版本庫路徑清單的設定鍵"
 msgid "missing --config=<config>"
 msgstr "缺少 --config=<設定>"
 
+#: builtin/for-each-repo.c
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "收到無效的組態 --config=%s"
+
 #: builtin/fsck.c
 msgid "unknown"
 msgstr "未知"
@@ -7619,13 +7694,14 @@ msgid "notice: %s points to an unborn branch (%s)"
 msgstr "注意:%s 指向一個尚未誕生的分支(%s)"
 
 #: builtin/fsck.c
-msgid "Checking cache tree"
-msgstr "正在檢查快取樹"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "正在檢查 %s 的快取樹"
 
 #: builtin/fsck.c
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s:cache-tree 中無效的 sha1 指標"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s:%s 的 cache-tree 中的 sha1 指標無效"
 
 #: builtin/fsck.c
 msgid "non-tree in cache-tree"
@@ -7633,8 +7709,18 @@ msgstr "cache-tree 中非樹狀物件"
 
 #: builtin/fsck.c
 #, c-format
-msgid "%s: invalid sha1 pointer in resolve-undo"
-msgstr "%s:resolve-undo 的 sha1 指針無效"
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s:%s 的 resolve-undo 中的 sha1 指標無效"
+
+#: builtin/fsck.c
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "無法讀取 “%s” 封裝的修訂版索引 (rev-index)"
+
+#: builtin/fsck.c
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "“%s” 封裝的修訂版索引 (rev-index) 無效"
 
 #: builtin/fsck.c
 msgid ""
@@ -7670,7 +7756,7 @@ msgstr "將索引亦作為檢查的頭節點"
 
 #: builtin/fsck.c
 msgid "make reflogs head nodes (default)"
-msgstr "將引用日誌作為檢查的 HEAD 節點(預設)"
+msgstr "將引用日誌作為檢查的 HEAD 節點(預設)"
 
 #: builtin/fsck.c
 msgid "also consider packs and alternate objects"
@@ -7841,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"
@@ -8152,7 +8238,6 @@ msgstr "grep:無法建立執行緒:%s"
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "為 %2$s 設定的執行緒數 (%1$d) 無效"
 
-#. #-#-#-#-#  grep.c.po  #-#-#-#-#
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
@@ -8224,7 +8309,7 @@ msgstr "用 textconv 過濾器處理二進位檔案"
 
 #: builtin/grep.c
 msgid "search in subdirectories (default)"
-msgstr "在子目錄中尋找(預設)"
+msgstr "在子目錄中尋找(預設)"
 
 #: builtin/grep.c
 msgid "descend at most <depth> levels"
@@ -8236,7 +8321,7 @@ msgstr "使用延伸的 POSIX 常規表示式"
 
 #: builtin/grep.c
 msgid "use basic POSIX regular expressions (default)"
-msgstr "使用基本的 POSIX 常規表示式(預設)"
+msgstr "使用基本的 POSIX 常規表示式(預設)"
 
 #: builtin/grep.c
 msgid "interpret patterns as fixed strings"
@@ -8581,13 +8666,21 @@ msgid "'git help config' for more information"
 msgstr "'git help config' 取得更多訊息"
 
 #: builtin/hook.c
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
 
 #: builtin/hook.c
 msgid "silently ignore missing requested <hook-name>"
 msgstr "靜默忽略不存在而請求的 <hook-name>"
 
+#: builtin/hook.c
+msgid "file to read into hooks' stdin"
+msgstr "要讀進掛鉤 stdin 的檔案"
+
 #: builtin/index-pack.c
 #, c-format
 msgid "object type mismatch at %s"
@@ -8799,150 +8892,61 @@ msgid "unable to rename temporary '*.%s' file to '%s'"
 msgstr "無法將「*.%s」暫存檔的檔名更改為「%s」"
 
 #: builtin/index-pack.c
-msgid "error while closing pack file"
-msgstr "關閉包檔案時發生錯誤"
-
-#: builtin/index-pack.c builtin/pack-objects.c
-#, c-format
-msgid "bad pack.indexVersion=%<PRIu32>"
-msgstr "無效的 pack.indexVersion=%<PRIu32>"
-
-#: builtin/index-pack.c
-#, c-format
-msgid "Cannot open existing pack file '%s'"
-msgstr "無法開啟現有包檔案 '%s'"
-
-#: builtin/index-pack.c
-#, c-format
-msgid "Cannot open existing pack idx file for '%s'"
-msgstr "無法為 %s 開啟包索引檔案"
-
-#: builtin/index-pack.c
-#, c-format
-msgid "non delta: %d object"
-msgid_plural "non delta: %d objects"
-msgstr[0] "非 delta:%d 個物件"
-
-#: builtin/index-pack.c
-#, c-format
-msgid "chain length = %d: %lu object"
-msgid_plural "chain length = %d: %lu objects"
-msgstr[0] "鏈長 = %d: %lu 物件"
-
-#: builtin/index-pack.c
-msgid "Cannot come back to cwd"
-msgstr "無法返回目前工作目錄"
-
-#: builtin/index-pack.c
-#, c-format
-msgid "bad %s"
-msgstr "錯誤選項 %s"
-
-#: builtin/index-pack.c builtin/init-db.c
-#, c-format
-msgid "unknown hash algorithm '%s'"
-msgstr "未知的「%s」雜湊算法"
-
-#: builtin/index-pack.c
-msgid "--stdin requires a git repository"
-msgstr "--stdin 需要一個 git 版本庫"
-
-#: builtin/index-pack.c
-msgid "--verify with no packfile name given"
-msgstr "--verify 沒有提供 packfile 名稱參數"
-
-#: builtin/index-pack.c builtin/unpack-objects.c
-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"
+msgid "error while closing pack file"
+msgstr "關閉包檔案時發生錯誤"
 
-#: builtin/init-db.c
+#: builtin/index-pack.c builtin/pack-objects.c
 #, c-format
-msgid "templates not found in %s"
-msgstr "沒有在 %s 中找到範本"
+msgid "bad pack.indexVersion=%<PRIu32>"
+msgstr "無效的 pack.indexVersion=%<PRIu32>"
 
-#: builtin/init-db.c
+#: builtin/index-pack.c
 #, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "沒有從 '%s' 複製範本:%s"
+msgid "Cannot open existing pack file '%s'"
+msgstr "無法開啟現有包檔案 '%s'"
 
-#: builtin/init-db.c
+#: builtin/index-pack.c
 #, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "ç\84¡æ\95\88ç\9a\84å\88\9då§\8bå\88\86æ\94¯å\90\8d稱ï¼\9a'%s'"
+msgid "Cannot open existing pack idx file for '%s'"
+msgstr "ç\84¡æ³\95ç\82º %s é\96\8bå\95\9få\8c\85ç´¢å¼\95æª\94æ¡\88"
 
-#: builtin/init-db.c
+#: builtin/index-pack.c
 #, c-format
-msgid "unable to handle file type %d"
-msgstr "不能處理 %d 類型的檔案"
+msgid "non delta: %d object"
+msgid_plural "non delta: %d objects"
+msgstr[0] "非 delta:%d 個物件"
 
-#: builtin/init-db.c
+#: builtin/index-pack.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 "嘗試以不同的雜湊值重新初始化版本庫"
+msgid "chain length = %d: %lu object"
+msgid_plural "chain length = %d: %lu objects"
+msgstr[0] "鏈長 = %d: %lu 物件"
 
-#: builtin/init-db.c
-#, c-format
-msgid "%s already exists"
-msgstr "%s 已經存在"
+#: builtin/index-pack.c
+msgid "Cannot come back to cwd"
+msgstr "無法返回目前工作目錄"
 
-#: builtin/init-db.c
+#: builtin/index-pack.c
 #, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: 忽略 --initial-branch=%s"
+msgid "bad %s"
+msgstr "錯誤選項 %s"
 
-#: builtin/init-db.c
+#: builtin/index-pack.c builtin/init-db.c setup.c
 #, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "重新初始化已存在的共享 Git 版本庫於 %s%s\n"
+msgid "unknown hash algorithm '%s'"
+msgstr "未知的「%s」雜湊算法"
 
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "重新初始化已存在的 Git 版本庫於 %s%s\n"
+#: builtin/index-pack.c
+msgid "--stdin requires a git repository"
+msgstr "--stdin 需要一個 git 版本庫"
 
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "已初始化空的共享 Git 版本庫於 %s%s\n"
+#: builtin/index-pack.c
+msgid "--verify with no packfile name given"
+msgstr "--verify 沒有提供 packfile 名稱參數"
 
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "已初始化空的 Git 版本庫於 %s%s\n"
+#: builtin/index-pack.c builtin/unpack-objects.c
+msgid "fsck error in pack objects"
+msgstr "在打包物件中 fsck 檢查發生錯誤"
 
 #: builtin/init-db.c
 msgid ""
@@ -9314,7 +9318,7 @@ msgstr "不包含已在上游提交中的修補檔"
 
 #: builtin/log.c
 msgid "show patch format instead of default (patch + stat)"
-msgstr "顯示純修補檔格式而非預設(修補檔+狀態)"
+msgstr "顯示純修補檔格式而非預設(修補檔+狀態)"
 
 #: builtin/log.c
 msgid "Messaging"
@@ -9330,7 +9334,7 @@ msgstr "新增信件頭"
 
 #: builtin/log.c
 msgid "email"
-msgstr "信件位址"
+msgstr "信"
 
 #: builtin/log.c
 msgid "add To: header"
@@ -9491,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 '('"
@@ -9528,7 +9537,7 @@ msgstr "使用小寫字母表示 'fsmonitor clean' 檔案"
 
 #: builtin/ls-files.c
 msgid "show cached files in the output (default)"
-msgstr "顯示快取的檔案(預設)"
+msgstr "顯示快取的檔案(預設)"
 
 #: builtin/ls-files.c
 msgid "show deleted files in the output"
@@ -9629,11 +9638,11 @@ msgstr ""
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 
 #: builtin/ls-remote.c
 msgid "do not print remote URL"
@@ -9675,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 '('"
@@ -9951,10 +9955,18 @@ msgstr "允許合並不相關的歷史"
 msgid "perform multiple merges, one per line of input"
 msgstr "執行多次合併,一次執行輸入一列"
 
+#: builtin/merge-tree.c
+msgid "specify a merge-base for the merge"
+msgstr "指定用來合併的合併基底"
+
 #: builtin/merge-tree.c
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge 和其他所有選項都不相容"
 
+#: builtin/merge-tree.c
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base 與 --stdin 不相容"
+
 #: builtin/merge-tree.c builtin/notes.c
 #, c-format
 msgid "malformed input line: '%s'."
@@ -10015,7 +10027,7 @@ msgstr "建立一個單獨的提交而不是做一次合併"
 
 #: builtin/merge.c builtin/pull.c
 msgid "perform a commit if the merge succeeds (default)"
-msgstr "如果合併成功,執行一次提交(預設)"
+msgstr "如果合併成功,執行一次提交(預設)"
 
 #: builtin/merge.c builtin/pull.c
 msgid "edit message before committing"
@@ -10023,7 +10035,7 @@ msgstr "在提交前編輯提交說明"
 
 #: builtin/merge.c
 msgid "allow fast-forward (default)"
-msgstr "允許快轉(預設)"
+msgstr "允許快轉(預設)"
 
 #: builtin/merge.c builtin/pull.c
 msgid "abort if fast-forward is not possible"
@@ -10206,7 +10218,7 @@ msgstr "對於 %s 沒有來自 %s 的遠端追蹤分支"
 msgid "Bad value '%s' in environment '%s'"
 msgstr "環境 '%2$s' 中存在壞的取值 '%1$s'"
 
-#: builtin/merge.c read-cache.c strbuf.c wrapper.c
+#: builtin/merge.c editor.c read-cache.c wrapper.c
 #, c-format
 msgid "could not close '%s'"
 msgstr "不能關閉 '%s'"
@@ -10585,7 +10597,7 @@ msgstr "註解從標準輸入收到的文字"
 
 #: builtin/name-rev.c
 msgid "allow to print `undefined` names (default)"
-msgstr "允許列印 `未定義` 的名稱(預設)"
+msgstr "允許列印 `未定義` 的名稱(預設)"
 
 #: builtin/name-rev.c
 msgid "dereference tags in the input (internal use)"
@@ -10597,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>"
@@ -10609,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>]"
@@ -10781,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 ""
@@ -11039,7 +11067,7 @@ msgstr "無法寫入位圖索引"
 msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
 msgstr "寫入 %<PRIu32> 個物件而預期 %<PRIu32> 個"
 
-#: builtin/pack-objects.c
+#: builtin/pack-objects.c builtin/repack.c
 msgid "disabling bitmap writing, as some objects are not being packed"
 msgstr "停用 bitmap 寫入,因為一些物件將不會被打包"
 
@@ -11205,6 +11233,14 @@ msgstr "不支援的索引版本 %s"
 msgid "bad index version '%s'"
 msgstr "壞的索引版本 '%s'"
 
+#: builtin/pack-objects.c
+msgid "show progress meter during object writing phase"
+msgstr "在物件寫入階段顯示進度列"
+
+#: builtin/pack-objects.c
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "顯示進度列時類似 --all-progress"
+
 #: builtin/pack-objects.c
 msgid "<version>[,<offset>]"
 msgstr "<版本>[,<位移>]"
@@ -11447,9 +11483,17 @@ msgstr ""
 "<git@vger.kernel.org> 讓我們知道您還在使用。\n"
 "感謝。\n"
 
+#: builtin/pack-redundant.c
+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"
@@ -11457,7 +11501,15 @@ msgstr "打包一切"
 
 #: builtin/pack-refs.c
 msgid "prune loose refs (default)"
-msgstr "剪除鬆散引用(預設)"
+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]"
@@ -11535,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 "
@@ -11650,9 +11710,9 @@ msgstr "更新尚未誕生的分支,變更新增至索引。"
 msgid "pull with rebase"
 msgstr "重定基底式拉取"
 
-#: builtin/pull.c
-msgid "please commit or stash them."
-msgstr "請提交或貯存它們。"
+#: builtin/pull.c builtin/rebase.c
+msgid "Please commit or stash them."
+msgstr "請提交或貯存修改。"
 
 #: builtin/pull.c
 #, c-format
@@ -11819,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."
@@ -11866,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
@@ -11900,9 +11960,9 @@ msgstr "「%s」的值無效"
 msgid "repository"
 msgstr "版本庫"
 
-#: builtin/push.c builtin/send-pack.c
-msgid "push all refs"
-msgstr "æ\8e¨é\80\81æ\89\80æ\9c\89å¼\95ç\94¨"
+#: builtin/push.c
+msgid "push all branches"
+msgstr "æ\8e¨é\80\81æ\89\80æ\9c\89å\88\86æ\94¯"
 
 #: builtin/push.c builtin/send-pack.c
 msgid "mirror all refs"
@@ -11913,8 +11973,8 @@ msgid "delete refs"
 msgstr "刪除引用"
 
 #: builtin/push.c
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "推送標籤(不能使用 --all or --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr "推送標籤(不能和 --all、--branches 或 --mirror 一起使用)"
 
 #: builtin/push.c builtin/send-pack.c
 msgid "force updates"
@@ -11972,7 +12032,7 @@ msgstr "需要遠端支援 atomic 事務"
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete 未接任何引用沒有意義"
 
-#: builtin/push.c
+#: builtin/push.c t/helper/test-bundle-uri.c
 #, c-format
 msgid "bad repository '%s'"
 msgstr "壞的版本庫 '%s'"
@@ -12237,11 +12297,20 @@ msgstr ""
 "\n"
 "因此 git 無法對其重定基底。"
 
+#: builtin/rebase.c
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "未知的 rebase-merges 模式:%s"
+
 #: builtin/rebase.c
 #, c-format
 msgid "could not switch to %s"
 msgstr "無法切換到 %s"
 
+#: builtin/rebase.c
+msgid "apply options and merge options cannot be used together"
+msgstr "套用選項與合併選項不得同時使用"
+
 #: builtin/rebase.c
 #, c-format
 msgid ""
@@ -12249,6 +12318,15 @@ msgid ""
 "\"ask\"."
 msgstr "無法識別的 '%s' 空類型;有效的數值有 \"drop\"、\"keep\" 跟 \"ask\"。"
 
+#: builtin/rebase.c
+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,功能相同。"
+
 #: builtin/rebase.c
 #, c-format
 msgid ""
@@ -12512,18 +12590,27 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr "開關 `C' 期望一個數字值"
 
-#: builtin/rebase.c
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "未知模式:%s"
-
 #: builtin/rebase.c
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy 需要 --merge 或 --interactive"
 
 #: builtin/rebase.c
-msgid "apply options and merge options cannot be used together"
-msgstr "套用選項與合併選項不得同時使用"
+msgid ""
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
+"autosquash"
+msgstr "apply 選項與 rebase.autoSquash 不相容。請考慮加上 --no-autosquash"
+
+#: builtin/rebase.c
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr "apply 選項與 rebase.rebaseMerges 不相容。請考慮加上 --no-rebase-merges"
+
+#: builtin/rebase.c
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr "apply 選項與 rebase.updateRefs 不相容。請考慮加上 --no-update-refs"
 
 #: builtin/rebase.c
 #, c-format
@@ -12572,10 +12659,6 @@ msgstr "'%s':只需要一個合併基礎"
 msgid "Does not point to a valid commit '%s'"
 msgstr "沒有指向一個有效的提交 '%s'"
 
-#: builtin/rebase.c
-msgid "Please commit or stash them."
-msgstr "請提交或貯存修改。"
-
 #: builtin/rebase.c
 msgid "HEAD is up to date."
 msgstr "HEAD 是最新的。"
@@ -12879,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"
@@ -13375,8 +13458,8 @@ msgid "approxidate"
 msgstr "近似日期"
 
 #: builtin/repack.c
-msgid "with -C, expire objects older than this"
-msgstr "搭配 -C 會將早於此的物件設為過期"
+msgid "with --cruft, expire objects older than this"
+msgstr "搭配 --cruft 會將早於此的物件標為過期"
 
 #: builtin/repack.c
 msgid "remove redundant packs, and run git-prune-packed"
@@ -13484,7 +13567,7 @@ msgstr "pack-objects 沒有為 %2$s-%3$s 套件包寫入 “%1$s” 檔案"
 #: builtin/repack.c sequencer.c
 #, c-format
 msgid "could not unlink: %s"
-msgstr "ç\84¡æ³\95å\8f\96æ¶\88é\80£çµ\90:%s"
+msgstr "ç\84¡æ³\95å\88ªé\99¤:%s"
 
 #: builtin/replace.c
 msgid "git replace [-f] <object> <replacement>"
@@ -14208,6 +14291,10 @@ msgstr ""
 msgid "remote name"
 msgstr "遠端名稱"
 
+#: builtin/send-pack.c
+msgid "push all refs"
+msgstr "推送所有引用"
+
 #: builtin/send-pack.c
 msgid "use stateless RPC protocol"
 msgstr "使用無狀態的 RPC 協定"
@@ -14462,9 +14549,11 @@ msgstr "顯示從標準輸入中讀入的不在本機版本庫中的引用"
 
 #: builtin/sparse-checkout.c
 msgid ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
-"git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 
 #: builtin/sparse-checkout.c
 msgid "this worktree is not sparse"
@@ -14605,6 +14694,27 @@ msgstr "必須在稀疏提交才能重新套用稀疏樣式 (sparsity pattern)"
 msgid "error while refreshing working directory"
 msgstr "重新整理工作目錄時發生錯誤"
 
+#: builtin/sparse-checkout.c
+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 <file>]"
+
+#: builtin/sparse-checkout.c
+msgid "terminate input and output files by a NUL character"
+msgstr "使用 NUL 字元終止輸入和輸出檔案"
+
+#: builtin/sparse-checkout.c
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
+"與 --rules-file 搭配使用時,將 patterns (模式) 解釋為 cone 模式的 patterns"
+
+#: builtin/sparse-checkout.c
+msgid "use patterns in <file> instead of the current ones."
+msgstr "使用 <file> 中的(而非目前使用的)模式。"
+
 #: builtin/stash.c
 msgid "git stash list [<log-options>]"
 msgstr "git stash list [<log-options>]"
@@ -15238,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"
@@ -15562,11 +15677,6 @@ msgstr "「%s」不是有效的子模組名稱"
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <command>"
 
-#: builtin/submodule--helper.c git.c
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s 不支援 --super-prefix"
-
 #: builtin/symbolic-ref.c
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <reason>] <name> <ref>"
@@ -16153,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]]"
@@ -16186,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"
@@ -16266,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 "簽出 <分支>,即使已經被簽出到其它工作區"
@@ -16283,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 "生成新的工作區"
@@ -16308,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 加入"
@@ -16468,6 +16654,11 @@ msgstr "只對除錯有用"
 msgid "core.fsyncMethod = batch is unsupported on this platform"
 msgstr "core.fsyncMethod = batch 不支援本平台"
 
+#: bundle-uri.c
+#, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "無法解析套件包清單鍵 %s 的值 “%s”"
+
 #: bundle-uri.c
 #, c-format
 msgid "bundle list at '%s' has no mode"
@@ -16481,6 +16672,15 @@ msgstr "無法建立暫存檔"
 msgid "insufficient capabilities"
 msgstr "功能不足"
 
+#: bundle-uri.c
+#, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "從 “%s” 下載的檔案不是套件包"
+
+#: bundle-uri.c
+msgid "failed to store maximum creation token"
+msgstr "無法儲存最大的建立權杖"
+
 #: bundle-uri.c
 #, c-format
 msgid "unrecognized bundle mode from URI '%s'"
@@ -16501,6 +16701,15 @@ msgstr "無法從 “%s” URI 下載套件包"
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "位於 URI “%s” 的檔案不是套件包或套件包清單"
 
+#: bundle-uri.c
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: 非預期的引數:“%s”"
+
+#: bundle-uri.c
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: 引數後應該有一個 flush 包"
+
 #: bundle-uri.c
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: 收到空白列"
@@ -16541,6 +16750,12 @@ msgstr "版本庫中缺少這些必備的提交:"
 msgid "need a repository to verify a bundle"
 msgstr "需要版本庫驗證套件包"
 
+#: bundle.c
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr "一些前提提交存在於物件儲存區,但未連接到版本庫的歷史記錄"
+
 #: bundle.c
 #, c-format
 msgid "The bundle contains this ref:"
@@ -16557,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 "無法複製套件包描述元"
@@ -16739,7 +16964,7 @@ msgstr "取得和設定版本庫或者全域選項"
 
 #: command-list.h
 msgid "Count unpacked number of objects and their disk consumption"
-msgstr "計算未打包物件的數量和磁碟空間用"
+msgstr "計算未打包物件的數量和磁碟空間用"
 
 #: command-list.h
 msgid "Retrieve and store user credentials"
@@ -16854,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"
@@ -17395,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"
@@ -17500,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 "正在掃描合併提交"
@@ -17535,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"
@@ -17586,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!"
@@ -18108,8 +18348,8 @@ msgid "bad zlib compression level %d"
 msgstr "錯誤的 zlib 壓縮級別 %d"
 
 #: config.c
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar 應該是一個字元"
+msgid "core.commentChar should only be one ASCII character"
+msgstr "core.commentChar 應該是一個 ASCII 字元"
 
 #: config.c
 #, c-format
@@ -18247,6 +18487,11 @@ msgstr "不能設定 '%s' 為 '%s'"
 msgid "invalid section name: %s"
 msgstr "無效的小節名稱:%s"
 
+#: config.c
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr "因為第 %2$<PRIuMAX> 列中 “%1$s” 的文字列太長,故拒絕運作"
+
 #: config.c
 #, c-format
 msgid "missing value for '%s'"
@@ -18315,17 +18560,26 @@ msgstr "伺服器指定的「%s」物件格式無效"
 
 #: connect.c
 #, c-format
-msgid "invalid ls-refs response: %s"
-msgstr "無效的 ls-refs 回應:%s"
+msgid "error on bundle-uri response line %d: %s"
+msgstr "在 bundle-uri 回應的第 %d 列發現錯誤:%s"
 
 #: connect.c
-msgid "expected flush after ref listing"
-msgstr "在引用列表之後應該有一個 flush 包"
+msgid "expected flush after bundle-uri listing"
+msgstr "在 bundle-uri 清單後應該有一個 flush 包"
 
 #: connect.c
 msgid "expected response end packet after ref listing"
 msgstr "在引用列表後預期要有回應結束封包"
 
+#: connect.c
+#, c-format
+msgid "invalid ls-refs response: %s"
+msgstr "無效的 ls-refs 回應:%s"
+
+#: connect.c
+msgid "expected flush after ref listing"
+msgstr "在引用列表之後應該有一個 flush 包"
+
 #: connect.c
 #, c-format
 msgid "protocol '%s' is not supported"
@@ -18718,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 [<選項>] <路徑> <路徑>"
@@ -18782,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"
@@ -18798,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"
@@ -18926,7 +19193,7 @@ msgstr "<參數1,參數2>..."
 #: diff.c
 msgid ""
 "output the distribution of relative amount of changes for each sub-directory"
-msgstr "輸出每個子目錄相對變更的分"
+msgstr "輸出每個子目錄相對變更的分"
 
 #: diff.c
 msgid "synonym for --dirstat=cumulative"
@@ -19038,6 +19305,10 @@ msgstr "輸出的每一行附加前綴"
 msgid "do not show any source or destination prefix"
 msgstr "不顯示任何來源和目的地前綴"
 
+#: diff.c
+msgid "use default prefixes a/ and b/"
+msgstr "使用預設的前置名稱 a/ 和 b/"
+
 #: diff.c
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr "顯示指定行數的差異區塊間的上下文"
@@ -19407,6 +19678,16 @@ msgstr "不能從 '%s' 遷移 git 目錄到 '%s'"
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "提示:等待您的編輯器關閉檔案...%c"
 
+#: editor.c sequencer.c wrapper.c
+#, c-format
+msgid "could not write to '%s'"
+msgstr "不能寫入 '%s'"
+
+#: editor.c
+#, c-format
+msgid "could not edit '%s'"
+msgstr "無法編輯 '%s'"
+
 #: entry.c
 msgid "Filtering content"
 msgstr "過濾內容"
@@ -19727,16 +20008,14 @@ 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 ""
 "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--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>]"
 
 #: git.c
 msgid ""
@@ -19765,11 +20044,6 @@ msgstr "未傳入目錄至「%s」選項\n"
 msgid "no namespace given for --namespace\n"
 msgstr "沒有為 --namespace 提供命名空間\n"
 
-#: git.c
-#, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "沒有為 --super-prefix 提供前綴\n"
-
 #: git.c
 #, c-format
 msgid "-c expects a configuration string\n"
@@ -19780,6 +20054,11 @@ msgstr "應為 -c 提供一個設定字串\n"
 msgid "no config key given for --config-env\n"
 msgstr "未傳入設定鍵至 --config-env\n"
 
+#: git.c
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "沒有為 --attr-source 提供屬性來源\n"
+
 #: git.c
 #, c-format
 msgid "unknown option: %s\n"
@@ -19904,8 +20183,13 @@ msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand 執行失敗:%s %s"
 
 #: gpg-interface.c
-msgid "gpg failed to sign the data"
-msgstr "gpg 無法為資料簽名"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg 無法簽名資料:\n"
+"%s"
 
 #: gpg-interface.c
 msgid "user.signingKey needs to be set for ssh signing"
@@ -20566,7 +20850,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"
 #.
 #: merge-ort.c
 #, c-format
@@ -20755,7 +21039,7 @@ msgstr "重新命名"
 
 #: merge-recursive.c
 msgid "renamed"
-msgstr "重新命名"
+msgstr "重新命名"
 
 #: merge-recursive.c
 #, c-format
@@ -21248,6 +21532,11 @@ msgstr "損壞的鬆散物件 '%s'"
 msgid "garbage at end of loose object '%s'"
 msgstr "鬆散物件 '%s' 後面有垃圾資料"
 
+#: object-file.c
+#, c-format
+msgid "unable to open loose object %s"
+msgstr "無法打開鬆散物件 %s"
+
 #: object-file.c
 #, c-format
 msgid "unable to parse %s header"
@@ -21269,19 +21558,14 @@ msgstr "%s 的標頭過長,超出 %d 位元組"
 
 #: object-file.c
 #, c-format
-msgid "failed to read object %s"
-msgstr "讀取物件 %s 失敗"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "鬆散物件 %s(儲存在 %s)已損壞"
 
 #: object-file.c
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "找不到 %2$s 的替代 %1$s"
 
-#: object-file.c
-#, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "鬆散物件 %s(儲存在 %s)已損壞"
-
 #: object-file.c
 #, c-format
 msgid "packed object %s (stored in %s) is corrupt"
@@ -21297,10 +21581,6 @@ msgstr "無法寫檔案 %s"
 msgid "unable to set permission to '%s'"
 msgstr "無法為 '%s' 設定權限"
 
-#: object-file.c
-msgid "file write error"
-msgstr "檔案寫錯誤"
-
 #: object-file.c
 msgid "error when closing loose object file"
 msgstr "關閉鬆散物件檔案時發生錯誤"
@@ -21359,12 +21639,13 @@ msgid "cannot read object for %s"
 msgstr "不能讀取物件 %s"
 
 #: object-file.c
-msgid "corrupt commit"
-msgstr "損壞的提交"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "物件 fsck 失敗:%s"
 
 #: object-file.c
-msgid "corrupt tag"
-msgstr "æ\90\8då£\9eç\9a\84æ¨\99籤"
+msgid "refusing to create malformed object"
+msgstr "æ\8b\92çµ\95建ç«\8bæ ¼å¼\8fé\8c¯èª¤ç\9a\84ç\89©ä»¶"
 
 #: object-file.c
 #, c-format
@@ -21433,7 +21714,7 @@ msgstr "%s [無效物件]"
 #. TRANSLATORS: This is a line of ambiguous commit
 #. object output. E.g.:
 #. *
-#.    "deadbeef commit 2021-01-01 - Some Commit Message"
+#. "deadbeef commit 2021-01-01 - Some Commit Message"
 #.
 #: object-name.c
 #, c-format
@@ -21443,7 +21724,7 @@ msgstr "%s 提交 %s - %s"
 #. TRANSLATORS: This is a line of ambiguous
 #. tag object output. E.g.:
 #. *
-#.    "deadbeef tag 2022-01-01 - Some Tag Message"
+#. "deadbeef tag 2022-01-01 - Some Tag Message"
 #. *
 #. The second argument is the YYYY-MM-DD found
 #. in the tag.
@@ -21460,7 +21741,7 @@ msgstr "%s 標籤 %s - %s"
 #. tag object output where we couldn't parse
 #. the tag itself. E.g.:
 #. *
-#.    "deadbeef [bad tag, could not parse it]"
+#. "deadbeef [bad tag, could not parse it]"
 #.
 #: object-name.c
 #, c-format
@@ -21675,11 +21956,6 @@ msgstr "位圖包索引的 XOR 偏移無效"
 msgid "cannot fstat bitmap file"
 msgstr "無法 fstat 位圖檔案"
 
-#: pack-bitmap.c
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "忽略多出來的位圖檔案:「%s」"
-
 #: pack-bitmap.c
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "總和檢查碼在 MIDX 和位圖中無符合項目"
@@ -21763,6 +22039,11 @@ msgstr "在「%2$s」封包,位移 %3$<PRIuMAX> 的地方找不到「%1$s」"
 msgid "unable to get disk usage of '%s'"
 msgstr "無法取得「%s」的磁碟用量"
 
+#: pack-bitmap.c
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "“%s” 位圖檔案的總和檢查碼無效"
+
 #: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s is too small"
@@ -21813,6 +22094,15 @@ msgstr "倒排索引檔案 %s 有不支援的版本 %<PRIu32>"
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "倒排索引檔案 %s 有不支援的雜湊 ID %<PRIu32>"
 
+#: pack-revindex.c
+msgid "invalid checksum"
+msgstr "無效的總和檢查碼"
+
+#: pack-revindex.c
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "%<PRIu64> 位置的修訂版索引 (rev-index) 無效:%<PRIu32> != %<PRIu32>"
+
 #: pack-write.c
 msgid "cannot both write and verify reverse index"
 msgstr "無法同時寫入和驗證倒排索引"
@@ -22006,6 +22296,10 @@ msgstr "更加安靜"
 msgid "use <n> digits to display object names"
 msgstr "用 <n> 位數字顯示物件名稱"
 
+#: parse-options.h
+msgid "prefixed path to initial superproject"
+msgstr "初始父專案的前綴路徑"
+
 #: parse-options.h
 msgid "how to strip spaces and #comments from message"
 msgstr "設定如何刪除提交說明裡的空格和 #備註"
@@ -22233,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)"
@@ -22421,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 --"
@@ -22587,6 +22900,16 @@ msgstr "落後 %d"
 msgid "ahead %d, behind %d"
 msgstr "領先 %d,落後 %d"
 
+#: ref-filter.c
+#, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) 不取引數"
+
+#: ref-filter.c
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "無法識別的 %%(%.*s) 引數:%s"
+
 #: ref-filter.c
 #, c-format
 msgid "expected format: %%(color:<color>)"
@@ -22609,49 +22932,44 @@ msgstr "期望整數值 refname:rstrip=%s"
 
 #: ref-filter.c
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "無法識別的 %%(%s) 參數:%s"
+msgid "expected %%(trailers:key=<value>)"
+msgstr "預期是 %%(trailers:key=<value>)"
 
 #: ref-filter.c
 #, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) 不帶參數"
+msgid "unknown %%(trailers) argument: %s"
+msgstr "未知的 %%(trailers) 參數:%s"
 
 #: ref-filter.c
 #, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) 不帶參數"
+msgid "positive value expected contents:lines=%s"
+msgstr "期望一個正數 contents:lines=%s"
 
 #: ref-filter.c
 #, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) 不帶參數"
+msgid "argument expected for %s"
+msgstr "引數預期 %s"
 
 #: ref-filter.c
 #, c-format
-msgid "expected %%(trailers:key=<value>)"
-msgstr "預期是 %%(trailers:key=<value>)"
+msgid "positive value expected %s=%s"
+msgstr "期望一個正數 %s=%s"
 
 #: ref-filter.c
 #, c-format
-msgid "unknown %%(trailers) argument: %s"
-msgstr "未知的 %%(trailers) 參數:%s"
+msgid "cannot fully parse %s=%s"
+msgstr "無法完全解析 %s=%s"
 
 #: ref-filter.c
 #, c-format
-msgid "positive value expected contents:lines=%s"
-msgstr "æ\9c\9fæ\9c\9bä¸\80å\80\8bæ­£æ\95¸ contents:lines=%s"
+msgid "value expected %s="
+msgstr "æ\95¸å\80¼é \90æ\9c\9f %s="
 
 #: ref-filter.c
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "%%(%2$s) 中的 '%1$s' 預期是正數值"
 
-#: ref-filter.c
-#, c-format
-msgid "unrecognized email option: %s"
-msgstr "無法識別的 email 選項:%s"
-
 #: ref-filter.c
 #, c-format
 msgid "expected format: %%(align:<width>,<position>)"
@@ -22667,6 +22985,11 @@ msgstr "無法識別的位置:%s"
 msgid "unrecognized width:%s"
 msgstr "無法識別的寬度:%s"
 
+#: ref-filter.c
+#, c-format
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "無法識別的 %%(%s) 參數:%s"
+
 #: ref-filter.c
 #, c-format
 msgid "positive width expected with the %%(align) atom"
@@ -22674,8 +22997,8 @@ msgstr "元素 %%(align) 需要一個正數的寬度"
 
 #: ref-filter.c
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) 未取引數"
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "預期格式:%%(ahead-behind:<committish>)"
 
 #: ref-filter.c
 #, c-format
@@ -22733,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)"
@@ -22810,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"
@@ -23339,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
@@ -23413,7 +23745,7 @@ msgstr "使用之前的解決方案解決 '%s'。"
 #: rerere.c
 #, c-format
 msgid "cannot unlink stray '%s'"
-msgstr "不能刪除 stray '%s'"
+msgstr "無法刪除失散檔案 “%s”"
 
 #: rerere.c
 #, c-format
@@ -23430,11 +23762,6 @@ msgstr "更新 '%s' 中的衝突狀態失敗"
 msgid "no remembered resolution for '%s'"
 msgstr "沒有為 '%s' 記憶的解決方案"
 
-#: rerere.c
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "不能刪除 '%s'"
-
 #: rerere.c
 #, c-format
 msgid "Updated preimage for '%s'"
@@ -23485,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 "您的目前分支好像被損壞"
@@ -23851,11 +24183,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "不能鎖定 '%s'"
 
-#: sequencer.c strbuf.c wrapper.c
-#, c-format
-msgid "could not write to '%s'"
-msgstr "不能寫入 '%s'"
-
 #: sequencer.c
 #, c-format
 msgid "could not write eol to '%s'"
@@ -24183,6 +24510,26 @@ msgstr "git %s:無法讀取索引"
 msgid "git %s: failed to refresh the index"
 msgstr "git %s:無法重新整理索引"
 
+#: sequencer.c
+#, c-format
+msgid "'%s' is not a valid label"
+msgstr "“%s” 不是有效的標籤"
+
+#: sequencer.c
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "“%s” 不是有效的引用名稱"
+
+#: sequencer.c
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr "update-ref 需要完全限定的引用名稱,比如:refs/heads/%s"
+
+#: sequencer.c
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "無效的命令 “%.*s”"
+
 #: sequencer.c
 #, c-format
 msgid "%s does not accept arguments: '%s'"
@@ -24273,10 +24620,6 @@ msgstr "嘗試 \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgid "could not create sequencer directory '%s'"
 msgstr "不能建立序列目錄 '%s'"
 
-#: sequencer.c
-msgid "could not lock HEAD"
-msgstr "不能鎖定 HEAD"
-
 #: sequencer.c
 msgid "no cherry-pick or revert in progress"
 msgstr "揀選或還原動作並未進行"
@@ -24392,22 +24735,22 @@ msgstr ""
 "\n"
 
 #: sequencer.c
-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 "並且更改索引和(或)工作區。\n"
 
 #: sequencer.c
 #, 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"
+"提交或貯存修改,然後執行\n"
 "\n"
 "  git rebase --continue\n"
 "\n"
@@ -24799,71 +25142,160 @@ msgid "cannot chdir to '%s'"
 msgstr "不能切換目錄到 '%s'"
 
 #: setup.c
-msgid "cannot come back to cwd"
-msgstr "無法返回目前工作目錄"
+msgid "cannot come back to cwd"
+msgstr "無法返回目前工作目錄"
+
+#: setup.c
+#, c-format
+msgid "failed to stat '%*s%s%s'"
+msgstr "取得 '%*s%s%s' 狀態(stat)失敗"
+
+#: setup.c
+msgid "Unable to read current working directory"
+msgstr "不能讀取目前工作目錄"
+
+#: setup.c
+#, c-format
+msgid "cannot change to '%s'"
+msgstr "不能切換到 '%s'"
+
+#: setup.c
+#, c-format
+msgid "not a git repository (or any of the parent directories): %s"
+msgstr "不是一個 git 版本庫(或者任何父目錄):%s"
+
+#: setup.c
+#, c-format
+msgid ""
+"not a git repository (or any parent up to mount point %s)\n"
+"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
+msgstr ""
+"不是一個 git 版本庫(或者直至掛載點 %s 的任何父目錄)\n"
+"停止在檔案系統邊界(未設定 GIT_DISCOVERY_ACROSS_FILESYSTEM)。"
+
+#: setup.c
+#, c-format
+msgid ""
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+msgstr ""
+"在位於「%s」的版本庫偵測到可疑所有權\n"
+"%s若要放行本目錄,請呼叫:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
+#: setup.c
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "無法使用 “%s” 純版本庫(safe.bareRepository 是 “%s”)"
+
+#: setup.c
+#, c-format
+msgid ""
+"problem with core.sharedRepository filemode value (0%.3o).\n"
+"The owner of files must always have read and write permissions."
+msgstr ""
+"參數 core.sharedRepository 的檔案屬性值有問題(0%.3o)。\n"
+"檔案所有者必須始終擁有讀寫權限。"
+
+#: setup.c
+msgid "fork failed"
+msgstr "fork 失敗"
+
+#: setup.c
+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 "failed to stat '%*s%s%s'"
-msgstr "取得 '%*s%s%s' 狀態(stat)失敗"
+msgid "invalid initial branch name: '%s'"
+msgstr "無效的初始分支名稱:'%s'"
 
 #: setup.c
-msgid "Unable to read current working directory"
-msgstr "不能讀取目前工作目錄"
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "不能處理 %d 類型的檔案"
 
 #: setup.c
 #, c-format
-msgid "cannot change to '%s'"
-msgstr "不能切換到 '%s'"
+msgid "unable to move %s to %s"
+msgstr "不能移動 %s 至 %s"
 
 #: setup.c
-#, c-format
-msgid "not a git repository (or any of the parent directories): %s"
-msgstr "不是一個 git 版本庫(或者任何父目錄):%s"
+msgid "attempt to reinitialize repository with different hash"
+msgstr "嘗試以不同的雜湊值重新初始化版本庫"
 
 #: setup.c
 #, c-format
-msgid ""
-"not a git repository (or any parent up to mount point %s)\n"
-"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
-msgstr ""
-"不是一個 git 版本庫(或者直至掛載點 %s 的任何父目錄)\n"
-"停止在檔案系統邊界(未設定 GIT_DISCOVERY_ACROSS_FILESYSTEM)。"
+msgid "%s already exists"
+msgstr "%s 已經存在"
 
 #: setup.c
 #, c-format
-msgid ""
-"detected dubious ownership in repository at '%s'\n"
-"%sTo add an exception for this directory, call:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-msgstr ""
-"在位於「%s」的版本庫偵測到可疑所有權\n"
-"%s若要放行本目錄,請呼叫:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: 忽略 --initial-branch=%s"
 
 #: setup.c
 #, c-format
-msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
-msgstr "無法使用 “%s” 純版本庫(safe.bareRepository 是 “%s”)"
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "重新初始化已存在的共享 Git 版本庫於 %s%s\n"
 
 #: setup.c
 #, c-format
-msgid ""
-"problem with core.sharedRepository filemode value (0%.3o).\n"
-"The owner of files must always have read and write permissions."
-msgstr ""
-"參數 core.sharedRepository 的檔案屬性值有問題(0%.3o)。\n"
-"檔案所有者必須始終擁有讀寫權限。"
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "重新初始化已存在的 Git 版本庫於 %s%s\n"
 
 #: setup.c
-msgid "fork failed"
-msgstr "fork 失敗"
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "已初始化空的共享 Git 版本庫於 %s%s\n"
 
 #: setup.c
-msgid "setsid failed"
-msgstr "setsid 失敗"
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "已初始化空的 Git 版本庫於 %s%s\n"
 
 #: sparse-index.c
 #, c-format
@@ -24924,11 +25356,6 @@ msgid "%u byte/s"
 msgid_plural "%u bytes/s"
 msgstr[0] "%u 位元組/秒"
 
-#: strbuf.c
-#, c-format
-msgid "could not edit '%s'"
-msgstr "無法編輯 '%s'"
-
 #: submodule-config.c
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
@@ -25139,6 +25566,19 @@ msgstr "ls-tree 返回未知返回值 %d"
 msgid "failed to lstat '%s'"
 msgstr "無法 lstat “%s”"
 
+#: t/helper/test-bundle-uri.c
+msgid "no remote configured to get bundle URIs from"
+msgstr "沒有設定可以用來取得套件包 URIs 的遠端"
+
+#: t/helper/test-bundle-uri.c
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "“%s” 遠端未設定 URL"
+
+#: t/helper/test-bundle-uri.c
+msgid "could not get the bundle-uri list"
+msgstr "無法取得 bundle-uri 清單"
+
 #: t/helper/test-cache-tree.c
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <options> (control|prime|update)"
@@ -25575,6 +26015,14 @@ msgstr "正在終止。"
 msgid "failed to push all needed submodules"
 msgstr "不能推送全部需要的子模組"
 
+#: transport.c
+msgid "bundle-uri operation not supported by protocol"
+msgstr "通訊協定不支援 bundle-uri 動作"
+
+#: transport.c
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "無法取得伺服器公佈的 bundle-uri 清單"
+
 #: tree-walk.c
 msgid "too-short tree object"
 msgstr "太短的樹狀物件"
@@ -26489,12 +26937,20 @@ msgstr "忽略的檔案"
 #: wt-status.c
 #, 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 ""
-"耗費了 %.2f 秒以枚舉未追蹤的檔案。'status -uno' 也許能提高速度,\n"
-"但您需要小心不要忘了新增新檔案(參見 'git help status')。"
+"列舉未追蹤檔案花費 %.2f 秒,\n"
+"不過已經快取結果,之後執行的速度或許能比較快。"
+
+#: wt-status.c
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "列舉未追蹤檔案花費 %.2f 秒。"
+
+#: wt-status.c
+msgid "See 'git help status' for information on how to improve this."
+msgstr "請參閱 “git help status” 深入了解如何改善。"
 
 #: wt-status.c
 #, c-format
@@ -26579,387 +27035,96 @@ msgstr "領先 "
 #. TRANSLATORS: the action is e.g. "pull with rebase"
 #: wt-status.c
 #, c-format
-msgid "cannot %s: You have unstaged changes."
-msgstr "不能%s:您有未暫存的變更。"
-
-#: wt-status.c
-msgid "additionally, your index contains uncommitted changes."
-msgstr "另外,您的索引中包含未提交的變更。"
-
-#: wt-status.c
-#, c-format
-msgid "cannot %s: Your index contains uncommitted changes."
-msgstr "不能%s:您的索引中包含未提交的變更。"
-
-#: git-merge-octopus.sh git-merge-resolve.sh
-msgid ""
-"Error: Your local changes to the following files would be overwritten by "
-"merge"
-msgstr "錯誤:您對下列檔案的本機修改將被合併動作覆蓋"
-
-#: git-merge-octopus.sh
-msgid "Automated merge did not work."
-msgstr "自動合併未生效。"
-
-#: git-merge-octopus.sh
-msgid "Should not be doing an octopus."
-msgstr "不應該執行章魚式合併。"
-
-#: git-merge-octopus.sh
-#, sh-format
-msgid "Unable to find common commit with $pretty_name"
-msgstr "無法找到和 $pretty_name 的基礎提交"
-
-#: git-merge-octopus.sh
-#, sh-format
-msgid "Already up to date with $pretty_name"
-msgstr "已經和 $pretty_name 保持一致"
-
-#: git-merge-octopus.sh
-#, sh-format
-msgid "Fast-forwarding to: $pretty_name"
-msgstr "快轉至:$pretty_name"
-
-#: git-merge-octopus.sh
-#, sh-format
-msgid "Trying simple merge with $pretty_name"
-msgstr "嘗試和 $pretty_name 的簡單合併"
-
-#: git-merge-octopus.sh
-msgid "Simple merge did not work, trying automatic merge."
-msgstr "簡單合併未生效,嘗試自動合併。"
-
-#: git-sh-setup.sh
-#, sh-format
-msgid "usage: $dashless $USAGE"
-msgstr "用法:$dashless $USAGE"
-
-#: git-sh-setup.sh
-#, sh-format
-msgid "Cannot chdir to $cdup, the toplevel of the working tree"
-msgstr "不能切換目錄到 $cdup,工作區的頂級目錄"
-
-#: git-sh-setup.sh
-#, sh-format
-msgid "fatal: $program_name cannot be used without a working tree."
-msgstr "致命錯誤:$program_name 不能在沒有工作區的情況下使用。"
-
-#: git-sh-setup.sh
-msgid "Cannot rewrite branches: You have unstaged changes."
-msgstr "不能重寫分支:您有未暫存的變更。"
-
-#: git-sh-setup.sh
-#, sh-format
-msgid "Cannot $action: You have unstaged changes."
-msgstr "不能 $action:您有未暫存的變更。"
-
-#: git-sh-setup.sh
-#, sh-format
-msgid "Cannot $action: Your index contains uncommitted changes."
-msgstr "不能 $action:您的索引中包含未提交的變更。"
-
-#: git-sh-setup.sh
-msgid "Additionally, your index contains uncommitted changes."
-msgstr "而且您的索引中包含未提交的變更。"
-
-#: git-sh-setup.sh
-msgid "You need to run this command from the toplevel of the working tree."
-msgstr "您需要在工作區的頂級目錄中執行這個指令。"
-
-#: git-sh-setup.sh
-msgid "Unable to determine absolute path of git directory"
-msgstr "不能確定 git 目錄的絕對路徑"
-
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#: git-add--interactive.perl
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %12s %s"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "建立了 %d 個路徑\n"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr "如果修補檔能完全套用,編輯區塊將立即標記為暫存。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr "如果修補檔能完全套用,編輯區塊將立即標記為貯存。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr "如果修補檔能完全套用,編輯區塊將立即標記為未暫存。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr "如果修補檔能完全套用,編輯區塊將立即標記為套用。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr "如果修補檔能完全套用,編輯塊將立即標記為捨棄。"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "為寫入開啟區塊編輯檔案失敗:%s"
-
-#: git-add--interactive.perl
-#, 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"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "無法讀取區塊編輯檔案:%s"
-
-#: git-add--interactive.perl
-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 - 不暫存此區塊和本檔案中後面的全部區塊"
-
-#: git-add--interactive.perl
-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 - 不貯存此區塊和本檔案中後面的全部區塊"
-
-#: git-add--interactive.perl
-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 - 不要不暫存此區塊和本檔案中後面的全部區塊"
-
-#: git-add--interactive.perl
-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 - 不要套用此區塊和本檔案中後面的全部區塊"
-
-#: git-add--interactive.perl
-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 "cannot %s: You have unstaged changes."
+msgstr "不能%s:您有未暫存的變更。"
 
-#: git-add--interactive.perl
-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 - 不要捨棄此區塊和本檔案中後面的全部區塊"
+#: wt-status.c
+msgid "additionally, your index contains uncommitted changes."
+msgstr "另外,您的索引中包含未提交的變更。"
 
-#: git-add--interactive.perl
-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 - 不要套用此區塊和本檔案中後面的全部區塊"
+#: wt-status.c
+#, c-format
+msgid "cannot %s: Your index contains uncommitted changes."
+msgstr "不能%s:您的索引中包含未提交的變更。"
 
-#: git-add--interactive.perl
+#: git-merge-octopus.sh git-merge-resolve.sh
 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 - 不要套用此區塊和本檔案中後面的全部區塊"
+"Error: Your local changes to the following files would be overwritten by "
+"merge"
+msgstr "錯誤:您對下列檔案的本機修改將被合併動作覆蓋"
 
-#: git-add--interactive.perl
-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"
+#: git-merge-octopus.sh
+msgid "Automated merge did not work."
+msgstr "自動合併未生效。"
+
+#: git-merge-octopus.sh
+msgid "Should not be doing an octopus."
+msgstr "不應該執行章魚式合併。"
 
-#: git-add--interactive.perl
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "選取區塊不能套用到索引!\n"
+#: git-merge-octopus.sh
+#, sh-format
+msgid "Unable to find common commit with $pretty_name"
+msgstr "無法找到和 $pretty_name 的基礎提交"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "忽ç\95¥æ\9cªå¥\97ç\94¨ç\9a\84ï¼\9a%s\n"
+#: git-merge-octopus.sh
+#, sh-format
+msgid "Already up to date with $pretty_name"
+msgstr "å·²ç¶\93å\92\8c $pretty_name ä¿\9dæ\8c\81ä¸\80è\87´"
 
-#: git-add--interactive.perl
-msgid "No other hunks to goto\n"
-msgstr "沒有其它可供跳轉的區塊\n"
+#: git-merge-octopus.sh
+#, sh-format
+msgid "Fast-forwarding to: $pretty_name"
+msgstr "快轉至:$pretty_name"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "無效數字:'%s'\n"
+#: git-merge-octopus.sh
+#, sh-format
+msgid "Trying simple merge with $pretty_name"
+msgstr "嘗試和 $pretty_name 的簡單合併"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "對不起,只有 %d 個可用區塊。\n"
+#: git-merge-octopus.sh
+msgid "Simple merge did not work, trying automatic merge."
+msgstr "簡單合併未生效,嘗試自動合併。"
 
-#: git-add--interactive.perl
-msgid "No other hunks to search\n"
-msgstr "沒有其它可供尋找的區塊\n"
+#: git-sh-setup.sh
+#, sh-format
+msgid "usage: $dashless $USAGE"
+msgstr "用法:$dashless $USAGE"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "錯誤的常規表示式 %s:%s\n"
+#: git-sh-setup.sh
+#, sh-format
+msgid "Cannot chdir to $cdup, the toplevel of the working tree"
+msgstr "不能切換目錄到 $cdup,工作區的頂級目錄"
+
+#: git-sh-setup.sh
+#, sh-format
+msgid "fatal: $program_name cannot be used without a working tree."
+msgstr "致命錯誤:$program_name 不能在沒有工作區的情況下使用。"
 
-#: git-add--interactive.perl
-msgid "No hunk matches the given pattern\n"
-msgstr "沒有和提供模式相符合的區塊\n"
+#: git-sh-setup.sh
+msgid "Cannot rewrite branches: You have unstaged changes."
+msgstr "不能重寫分支:您有未暫存的變更。"
 
-#: git-add--interactive.perl
-msgid "No previous hunk\n"
-msgstr "沒有上一個區塊\n"
+#: git-sh-setup.sh
+#, sh-format
+msgid "Cannot $action: You have unstaged changes."
+msgstr "不能 $action:您有未暫存的變更。"
 
-#: git-add--interactive.perl
-msgid "No next hunk\n"
-msgstr "沒有下一個區塊\n"
+#: git-sh-setup.sh
+#, sh-format
+msgid "Cannot $action: Your index contains uncommitted changes."
+msgstr "不能 $action:您的索引中包含未提交的變更。"
 
-#: git-add--interactive.perl
-msgid "Sorry, cannot split this hunk\n"
-msgstr "對不起,不能分割這個區塊\n"
+#: git-sh-setup.sh
+msgid "Additionally, your index contains uncommitted changes."
+msgstr "而且您的索引中包含未提交的變更。"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "分割為 %d 塊。\n"
-
-#: git-add--interactive.perl
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "對不起,不能編輯這個區塊\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-#: git-add--interactive.perl
-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"
-
-#: git-add--interactive.perl
-msgid "missing --"
-msgstr "缺少 --"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "未知的 --patch 模式:%s"
+#: git-sh-setup.sh
+msgid "You need to run this command from the toplevel of the working tree."
+msgstr "您需要在工作區的頂級目錄中執行這個指令。"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "無效的參數 %s,期望是 --"
+#: git-sh-setup.sh
+msgid "Unable to determine absolute path of git directory"
+msgstr "不能確定 git 目錄的絕對路徑"
 
 #: git-send-email.perl
 msgid "local zone differs from GMT by a non-minute interval\n"
@@ -27282,14 +27447,19 @@ msgstr "(%s) 不能執行 '%s'"
 
 #: git-send-email.perl
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) 新增 %s: %s 自:'%s'\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) 從 “%s” 讀到格式錯誤的輸出"
 
 #: git-send-email.perl
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) 無法關閉管道至 '%s'"
 
+#: git-send-email.perl
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) 新增 %s: %s 自:'%s'\n"
+
 #: git-send-email.perl
 msgid "cannot send message as 7bit"
 msgstr "不能以 7bit 形式傳送訊息"
@@ -27334,6 +27504,376 @@ 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 "尚未追蹤目前的工作目錄"
+
+#~ msgid "cannot use --contents with final commit object name"
+#~ msgstr "無法將 --contents 與最終的提交物件名稱共用"
+
+#~ msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
+#~ msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
+
+#~ msgid "won't bisect on cg-seek'ed tree"
+#~ msgstr "不會在做了 cg-seek 的樹狀物件上進行二分搜尋"
+
+#~ msgid "--bisect-terms requires 0 or 1 argument"
+#~ msgstr "--bisect-terms 需要 0 或 1 個引數"
+
+#~ msgid "--bisect-next requires 0 arguments"
+#~ msgstr "--bisect-next 需要 0 個引數"
+
+#~ msgid "--bisect-log requires 0 arguments"
+#~ msgstr "--bisect-log 需要 0 個引數"
+
+#~ msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
+#~ msgstr "git env--helper --type=[bool|ulong] <選項> <環境變數>"
+
+#~ msgid "default for git_env_*(...) to fall back on"
+#~ msgstr "git_env_*(...) 的預設值"
+
+#~ msgid "be quiet only use git_env_*() value as exit code"
+#~ msgstr "安靜模式,只使用 git_env_*() 的值作為離開碼"
+
+#, c-format
+#~ msgid ""
+#~ "option `--default' expects a boolean value with `--type=bool`, not `%s`"
+#~ msgstr "選項「--default」預期收到「--type=bool」的布林值,而非「%s」"
+
+#, c-format
+#~ msgid ""
+#~ "option `--default' expects an unsigned long value with `--type=ulong`, "
+#~ "not `%s`"
+#~ msgstr ""
+#~ "選項「--default」預期收到「--type=ulong」的無號 long 數值,而非「%s」"
+
+#~ msgid "please commit or stash them."
+#~ msgstr "請提交或貯存它們。"
+
+#, c-format
+#~ msgid "Unknown mode: %s"
+#~ msgstr "未知模式:%s"
+
+#, c-format
+#~ msgid "%s doesn't support --super-prefix"
+#~ msgstr "%s 不支援 --super-prefix"
+
+#, c-format
+#~ msgid "no prefix given for --super-prefix\n"
+#~ msgstr "沒有為 --super-prefix 提供前綴\n"
+
+#, c-format
+#~ msgid "failed to read object %s"
+#~ msgstr "讀取物件 %s 失敗"
+
+#~ msgid "file write error"
+#~ msgstr "檔案寫錯誤"
+
+#~ msgid "corrupt commit"
+#~ msgstr "損壞的提交"
+
+#~ msgid "corrupt tag"
+#~ msgstr "損壞的標籤"
+
+#, c-format
+#~ msgid "%%(objecttype) does not take arguments"
+#~ msgstr "%%(objecttype) 不帶參數"
+
+#, c-format
+#~ msgid "%%(deltabase) does not take arguments"
+#~ msgstr "%%(deltabase) 不帶參數"
+
+#, c-format
+#~ msgid "%%(body) does not take arguments"
+#~ msgstr "%%(body) 不帶參數"
+
+#, c-format
+#~ msgid "unrecognized email option: %s"
+#~ msgstr "無法識別的 email 選項:%s"
+
+#~ msgid "could not lock HEAD"
+#~ msgstr "不能鎖定 HEAD"
+
+#, 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')."
+#~ msgstr ""
+#~ "耗費了 %.2f 秒以枚舉未追蹤的檔案。'status -uno' 也許能提高速度,\n"
+#~ "但您需要小心不要忘了新增新檔案(參見 'git help status')。"
+
+#, 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"
+
+#~ 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"
+
+#~ msgid "No other hunks to goto\n"
+#~ msgstr "沒有其它可供跳轉的區塊\n"
+
+#, 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"
+
+#~ msgid "No other hunks to search\n"
+#~ msgstr "沒有其它可供尋找的區塊\n"
+
+#, 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 "對不起,不能分割這個區塊\n"
+
+#, perl-format
+#~ msgid "Split into %d hunk.\n"
+#~ msgid_plural "Split into %d hunks.\n"
+#~ msgstr[0] "分割為 %d 塊。\n"
+
+#~ msgid "Sorry, cannot edit this hunk\n"
+#~ msgstr "對不起,不能編輯這個區塊\n"
+
+#~ 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,期望是 --"
+
 #, c-format
 #~ msgid "unable to normalize object directory: %s"
 #~ msgstr "無法規範化物件目錄: %s"
index 100f7a374dca1b8ffaae1ae9a2c00011d05a208a..e44530c80cf51edfdff846ed476a16c9bae0047a 100644 (file)
@@ -1,14 +1,20 @@
 /*
  * 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 "preload-index.h"
 #include "progress.h"
+#include "read-cache.h"
 #include "thread-utils.h"
 #include "repository.h"
+#include "symlinks.h"
+#include "trace2.h"
 
 /*
  * Mostly randomly chosen maximum thread counts: we
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 1e1e21878c833d54b165b0aa6d9720eb16536a94..718530bbab5204b88972849abb95eabd0d3bedaf 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1,8 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.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"
+#include "pager.h"
 #include "revision.h"
 #include "string-list.h"
 #include "mailmap.h"
@@ -13,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
@@ -51,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;
@@ -719,7 +726,7 @@ const char *repo_logmsg_reencode(struct repository *r,
                 * Otherwise, we still want to munge the encoding header in the
                 * result, which will be done by modifying the buffer. If we
                 * are using a fresh copy, we can reuse it. But if we are using
-                * the cached copy from get_commit_buffer, we need to duplicate it
+                * the cached copy from repo_get_commit_buffer, we need to duplicate it
                 * to avoid munging the cached copy.
                 */
                if (msg == get_cached_commit_buffer(r, commit, NULL))
@@ -1245,6 +1252,27 @@ static int format_trailer_match_cb(const struct strbuf *key, void *ud)
        return 0;
 }
 
+static struct strbuf *expand_separator(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,
@@ -1273,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_separator(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_separator(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) &&
@@ -1381,7 +1397,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;
 
@@ -1799,7 +1815,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 {
@@ -1838,10 +1854,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;
 
@@ -1857,40 +1873,34 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
        return consumed + 1;
 }
 
-static size_t userformat_want_item(struct strbuf *sb, 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;
+               }
+       }
 }
 
 void repo_format_commit_message(struct repository *r,
@@ -1907,7 +1917,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);
 
        /*
@@ -2199,12 +2218,14 @@ void pretty_print_commit(struct pretty_print_context *pp,
        int need_8bit_cte = pp->need_8bit_cte;
 
        if (pp->fmt == CMIT_FMT_USERFORMAT) {
-               format_commit_message(commit, user_format, sb, pp);
+               repo_format_commit_message(the_repository, commit,
+                                          user_format, sb, pp);
                return;
        }
 
        encoding = get_log_output_encoding();
-       msg = reencoded = logmsg_reencode(commit, NULL, encoding);
+       msg = reencoded = repo_logmsg_reencode(the_repository, commit, NULL,
+                                              encoding);
 
        if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
                indent = 0;
@@ -2261,7 +2282,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
        if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
 
-       unuse_commit_buffer(commit, reencoded);
+       repo_unuse_commit_buffer(the_repository, commit, reencoded);
 }
 
 void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
index f34e24c53a4925aec51cd62117654fdd5f7f980e..421209e9ec2732e1a08b130a6895d2688a28f52e 100644 (file)
--- a/pretty.h
+++ b/pretty.h
@@ -1,11 +1,11 @@
 #ifndef PRETTY_H
 #define PRETTY_H
 
-#include "cache.h"
 #include "date.h"
 #include "string-list.h"
 
 struct commit;
+struct repository;
 struct strbuf;
 struct process_trailer_options;
 
@@ -120,10 +120,6 @@ void repo_format_commit_message(struct repository *r,
                        const struct commit *commit,
                        const char *format, struct strbuf *sb,
                        const struct pretty_print_context *context);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define format_commit_message(c, f, s, con) \
-       repo_format_commit_message(the_repository, c, f, s, con)
-#endif
 
 /*
  * Parse given arguments from "arg", check it for correctness and
@@ -153,6 +149,8 @@ int commit_format_is_empty(enum cmit_fmt);
 /* Make subject of commit message suitable for filename */
 void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len);
 
+int has_non_ascii(const char *text);
+
 /*
  * Set values of fields in "struct process_trailer_options"
  * according to trailers arguments.
index d31b48e725083654222842049e121a35fe8d511b..450775a37492082130211431229ce5645ae17613 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "prio-queue.h"
 
 static inline int compare(struct prio_queue *queue, int i, int j)
index 0cdd875d37f166bedbbeb5f0e889046674ed58be..f695798acac72bd703dfacc59f83054fd761b619 100644 (file)
@@ -9,11 +9,13 @@
  */
 
 #define GIT_TEST_PROGRESS_ONLY
-#include "cache.h"
-#include "gettext.h"
+#include "git-compat-util.h"
+#include "pager.h"
 #include "progress.h"
+#include "repository.h"
 #include "strbuf.h"
 #include "trace.h"
+#include "trace2.h"
 #include "utf8.h"
 #include "config.h"
 
@@ -59,7 +61,7 @@ void progress_test_force_update(void)
 }
 
 
-static void progress_interval(int signum)
+static void progress_interval(int signum UNUSED)
 {
        progress_update = 1;
 }
index faa7612941cc2a70bf24f9dff2c02f2c5a2c0428..ac3aa1e365760596990188548410a16900e005d7 100644 (file)
@@ -1,7 +1,10 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
 #include "promisor-remote.h"
 #include "config.h"
+#include "trace2.h"
 #include "transport.h"
 #include "strvec.h"
 #include "packfile.h"
@@ -97,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 df36eb08efc2e194b6fc4f770235fb9707770de6..2cb9eda9ea46a9c004757693fc230dc90cebfc50 100644 (file)
@@ -18,24 +18,9 @@ struct promisor_remote {
 };
 
 void repo_promisor_remote_reinit(struct repository *r);
-static inline void promisor_remote_reinit(void)
-{
-       repo_promisor_remote_reinit(the_repository);
-}
-
 void promisor_remote_clear(struct promisor_remote_config *config);
-
 struct promisor_remote *repo_promisor_remote_find(struct repository *r, const char *remote_name);
-static inline struct promisor_remote *promisor_remote_find(const char *remote_name)
-{
-       return repo_promisor_remote_find(the_repository, remote_name);
-}
-
 int repo_has_promisor_remote(struct repository *r);
-static inline int has_promisor_remote(void)
-{
-       return repo_has_promisor_remote(the_repository);
-}
 
 /*
  * Fetches all requested objects from all promisor remotes, trying them one at
index 50df17279d1d5b2615fb8dd5a13853a2ea87b8eb..3baa33f63d87a675947bafcdfe3a798b02410de2 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
 #include "run-command.h"
 #include "strbuf.h"
 #include "prompt.h"
index bbde91810ac6667a1ee624d112ad26cf23776b1e..808a68c974ab7715513657c62d238aae8d3af07f 100644 (file)
@@ -1,11 +1,13 @@
 #include "git-compat-util.h"
 #include "protocol-caps.h"
 #include "gettext.h"
+#include "hex.h"
 #include "pkt-line.h"
 #include "strvec.h"
-#include "hash.h"
+#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"
 
@@ -77,7 +79,7 @@ static void send_info(struct repository *r, struct packet_writer *writer,
 
 int cap_object_info(struct repository *r, struct packet_reader *request)
 {
-       struct requested_info info;
+       struct requested_info info = { 0 };
        struct packet_writer writer;
        struct string_list oid_str_list = STRING_LIST_INIT_DUP;
 
index c53f7df5be4abae7a4f5792f42e4c4ecac006e9a..079ba75acf4e84451a80aa764cad3ac77a7d667f 100644 (file)
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
 #include "protocol.h"
+#include "trace2.h"
 
 static enum protocol_version parse_protocol_version(const char *value)
 {
index cef1a4a01c7902b0b1181a43580639fcead442ff..de66bf80f8409370069fed46ce97dadb25519d7d 100644 (file)
@@ -1,6 +1,27 @@
 #ifndef PROTOCOL_H
 #define PROTOCOL_H
 
+/*
+ * Intensive research over the course of many years has shown that
+ * port 9418 is totally unused by anything else. Or
+ *
+ *     Your search - "port 9418" - did not match any documents.
+ *
+ * as www.google.com puts it.
+ *
+ * This port has been properly assigned for git use by IANA:
+ * git (Assigned-9418) [I06-050728-0001].
+ *
+ *     git  9418/tcp   git pack transfer service
+ *     git  9418/udp   git pack transfer service
+ *
+ * with Linus Torvalds <torvalds@osdl.org> as the point of
+ * contact. September 2005.
+ *
+ * See http://www.iana.org/assignments/port-numbers
+ */
+#define DEFAULT_GIT_PORT 9418
+
 enum protocol_version {
        protocol_unknown_version = -1,
        protocol_v0 = 0,
index 261520b472c9c2bbac57ea94460dcabeefb3a91b..e54daf740a26345a182eb67d7ab2716916e41c37 100644 (file)
@@ -1,4 +1,7 @@
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.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 26719d21d1e7555d92289b26402a73030e330606..3c05194496f65f879f437abd29823986ef118f47 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "path.h"
 #include "quote.h"
+#include "strbuf.h"
 #include "strvec.h"
 
 int quote_path_fully = 1;
diff --git a/quote.h b/quote.h
index 87ff458b06dd6430855b39f6cb4833664e630746..0300c291041b02464e55e36a6c820a9faecf260f 100644 (file)
--- a/quote.h
+++ b/quote.h
@@ -3,6 +3,8 @@
 
 struct strbuf;
 
+extern int quote_path_fully;
+
 /* Help to copy the thing properly quoted for the shell safety.
  * any single quote is replaced with '\'', any exclamation point
  * is replaced with '\!', and the whole thing is enclosed in a
index 4bd65ab7496ebf8c6f0ca9420ff16e8532cce71d..2e86063491e11fcf9162da016be8471f603e07a2 100644 (file)
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
+#include "gettext.h"
 #include "range-diff.h"
+#include "object-name.h"
 #include "string-list.h"
 #include "run-command.h"
 #include "strvec.h"
@@ -8,7 +11,9 @@
 #include "linear-assignment.h"
 #include "diffcore.h"
 #include "commit.h"
+#include "pager.h"
 #include "pretty.h"
+#include "repository.h"
 #include "userdiff.h"
 #include "apply.h"
 #include "revision.h"
@@ -94,7 +99,7 @@ static int read_patches(const char *range, struct string_list *list,
                                strbuf_reset(&buf);
                        }
                        CALLOC_ARRAY(util, 1);
-                       if (get_oid(p, &util->oid)) {
+                       if (repo_get_oid(the_repository, p, &util->oid)) {
                                error(_("could not parse commit '%s'"), p);
                                FREE_AND_NULL(util);
                                string_list_clear(list, 1);
@@ -390,7 +395,7 @@ static void output_pair_header(struct diff_options *diffopt,
 
        if (!dashes->len)
                strbuf_addchars(dashes, '-',
-                               strlen(find_unique_abbrev(oid, abbrev)));
+                               strlen(repo_find_unique_abbrev(the_repository, oid, abbrev)));
 
        if (!b_util) {
                color = color_old;
@@ -412,7 +417,7 @@ static void output_pair_header(struct diff_options *diffopt,
                strbuf_addf(buf, "%*s:  %s ", patch_no_width, "-", dashes->buf);
        else
                strbuf_addf(buf, "%*d:  %s ", patch_no_width, a_util->i + 1,
-                           find_unique_abbrev(&a_util->oid, abbrev));
+                           repo_find_unique_abbrev(the_repository, &a_util->oid, abbrev));
 
        if (status == '!')
                strbuf_addf(buf, "%s%s", color_reset, color);
@@ -424,7 +429,7 @@ static void output_pair_header(struct diff_options *diffopt,
                strbuf_addf(buf, " %*s:  %s", patch_no_width, "-", dashes->buf);
        else
                strbuf_addf(buf, " %*d:  %s", patch_no_width, b_util->i + 1,
-                           find_unique_abbrev(&b_util->oid, abbrev));
+                           repo_find_unique_abbrev(the_repository, &b_util->oid, abbrev));
 
        commit = lookup_commit_reference(the_repository, oid);
        if (commit) {
@@ -485,7 +490,7 @@ static void output(struct string_list *a, struct string_list *b,
        if (range_diff_opts->diffopt)
                memcpy(&opts, range_diff_opts->diffopt, sizeof(opts));
        else
-               diff_setup(&opts);
+               repo_diff_setup(the_repository, &opts);
 
        opts.no_free = 1;
        if (!opts.output_format)
@@ -588,7 +593,7 @@ int is_range_diff_range(const char *arg)
        int i, positive = 0, negative = 0;
        struct rev_info revs;
 
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        if (setup_revisions(3, argv, &revs, NULL) == 1) {
                for (i = 0; i < revs.pending.nr; i++)
                        if (revs.pending.objects[i].item->flags & UNINTERESTING)
index aba63ebeb3be784a1fba95e13070e8bd847315c1..0ce8f83e56a9b42400b8ec792b19deb3a69ddb6e 100644 (file)
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
 #include "refs.h"
 #include "tag.h"
 #include "commit.h"
 #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;
@@ -48,7 +52,9 @@ static int add_one_ref(const char *path, const struct object_id *oid,
  * The traversal will have already marked us as SEEN, so we
  * only need to handle any progress reporting here.
  */
-static void mark_object(struct object *obj, const char *name, void *data)
+static void mark_object(struct object *obj UNUSED,
+                       const char *name UNUSED,
+                       void *data)
 {
        update_progress(data);
 }
@@ -63,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,
@@ -74,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;
 
        /*
@@ -152,7 +227,8 @@ static int add_recent_loose(const struct object_id *oid,
 }
 
 static int add_recent_packed(const struct object_id *oid,
-                            struct packed_git *p, uint32_t pos,
+                            struct packed_git *p,
+                            uint32_t pos,
                             void *data)
 {
        struct object *obj;
@@ -188,24 +264,32 @@ 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,
                             enum object_type type,
-                            int exclude,
-                            uint32_t name_hash,
-                            struct packed_git *found_pack,
-                            off_t found_offset)
+                            int exclude UNUSED,
+                            uint32_t name_hash UNUSED,
+                            struct packed_git *found_pack UNUSED,
+                            off_t found_offset UNUSED)
 {
        struct object *obj = lookup_object_by_type(the_repository, oid, type);
        if (!obj)
diff --git a/read-cache-ll.h b/read-cache-ll.h
new file mode 100644 (file)
index 0000000..9a1a7ed
--- /dev/null
@@ -0,0 +1,481 @@
+#ifndef READ_CACHE_LL_H
+#define READ_CACHE_LL_H
+
+#include "hash-ll.h"
+#include "hashmap.h"
+#include "statinfo.h"
+
+/*
+ * Basic data structures for the directory cache
+ */
+
+#define CACHE_SIGNATURE 0x44495243     /* "DIRC" */
+struct cache_header {
+       uint32_t hdr_signature;
+       uint32_t hdr_version;
+       uint32_t hdr_entries;
+};
+
+#define INDEX_FORMAT_LB 2
+#define INDEX_FORMAT_UB 4
+
+struct cache_entry {
+       struct hashmap_entry ent;
+       struct stat_data ce_stat_data;
+       unsigned int ce_mode;
+       unsigned int ce_flags;
+       unsigned int mem_pool_allocated;
+       unsigned int ce_namelen;
+       unsigned int index;     /* for link extension */
+       struct object_id oid;
+       char name[FLEX_ARRAY]; /* more */
+};
+
+#define CE_STAGEMASK (0x3000)
+#define CE_EXTENDED  (0x4000)
+#define CE_VALID     (0x8000)
+#define CE_STAGESHIFT 12
+
+/*
+ * Range 0xFFFF0FFF in ce_flags is divided into
+ * two parts: in-memory flags and on-disk ones.
+ * Flags in CE_EXTENDED_FLAGS will get saved on-disk
+ * if you want to save a new flag, add it in
+ * CE_EXTENDED_FLAGS
+ *
+ * In-memory only flags
+ */
+#define CE_UPDATE            (1 << 16)
+#define CE_REMOVE            (1 << 17)
+#define CE_UPTODATE          (1 << 18)
+#define CE_ADDED             (1 << 19)
+
+#define CE_HASHED            (1 << 20)
+#define CE_FSMONITOR_VALID   (1 << 21)
+#define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
+#define CE_CONFLICTED        (1 << 23)
+
+#define CE_UNPACKED          (1 << 24)
+#define CE_NEW_SKIP_WORKTREE (1 << 25)
+
+/* used to temporarily mark paths matched by pathspecs */
+#define CE_MATCHED           (1 << 26)
+
+#define CE_UPDATE_IN_BASE    (1 << 27)
+#define CE_STRIP_NAME        (1 << 28)
+
+/*
+ * Extended on-disk flags
+ */
+#define CE_INTENT_TO_ADD     (1 << 29)
+#define CE_SKIP_WORKTREE     (1 << 30)
+/* CE_EXTENDED2 is for future extension */
+#define CE_EXTENDED2         (1U << 31)
+
+#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
+
+/*
+ * Safeguard to avoid saving wrong flags:
+ *  - CE_EXTENDED2 won't get saved until its semantic is known
+ *  - Bits in 0x0000FFFF have been saved in ce_flags already
+ *  - Bits in 0x003F0000 are currently in-memory flags
+ */
+#if CE_EXTENDED_FLAGS & 0x803FFFFF
+#error "CE_EXTENDED_FLAGS out of range"
+#endif
+
+/* Forward structure decls */
+struct pathspec;
+struct tree;
+
+/*
+ * Copy the sha1 and stat state of a cache entry from one to
+ * another. But we never change the name, or the hash state!
+ */
+static inline void copy_cache_entry(struct cache_entry *dst,
+                                   const struct cache_entry *src)
+{
+       unsigned int state = dst->ce_flags & CE_HASHED;
+       int mem_pool_allocated = dst->mem_pool_allocated;
+
+       /* Don't copy hash chain and name */
+       memcpy(&dst->ce_stat_data, &src->ce_stat_data,
+                       offsetof(struct cache_entry, name) -
+                       offsetof(struct cache_entry, ce_stat_data));
+
+       /* Restore the hash state */
+       dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
+
+       /* Restore the mem_pool_allocated flag */
+       dst->mem_pool_allocated = mem_pool_allocated;
+}
+
+static inline unsigned create_ce_flags(unsigned stage)
+{
+       return (stage << CE_STAGESHIFT);
+}
+
+#define ce_namelen(ce) ((ce)->ce_namelen)
+#define ce_size(ce) cache_entry_size(ce_namelen(ce))
+#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
+#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
+#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
+#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
+
+#define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
+
+#define SOMETHING_CHANGED      (1 << 0) /* unclassified changes go here */
+#define CE_ENTRY_CHANGED       (1 << 1)
+#define CE_ENTRY_REMOVED       (1 << 2)
+#define CE_ENTRY_ADDED         (1 << 3)
+#define RESOLVE_UNDO_CHANGED   (1 << 4)
+#define CACHE_TREE_CHANGED     (1 << 5)
+#define SPLIT_INDEX_ORDERED    (1 << 6)
+#define UNTRACKED_CHANGED      (1 << 7)
+#define FSMONITOR_CHANGED      (1 << 8)
+
+struct split_index;
+struct untracked_cache;
+struct progress;
+struct pattern_list;
+
+enum sparse_index_mode {
+       /*
+        * There are no sparse directories in the index at all.
+        *
+        * Repositories that don't use cone-mode sparse-checkout will
+        * always have their indexes in this mode.
+        */
+       INDEX_EXPANDED = 0,
+
+       /*
+        * The index has already been collapsed to sparse directories
+        * whereever possible.
+        */
+       INDEX_COLLAPSED,
+
+       /*
+        * The sparse directories that exist are outside the
+        * sparse-checkout boundary, but it is possible that some file
+        * entries could collapse to sparse directory entries.
+        */
+       INDEX_PARTIALLY_SPARSE,
+};
+
+struct index_state {
+       struct cache_entry **cache;
+       unsigned int version;
+       unsigned int cache_nr, cache_alloc, cache_changed;
+       struct string_list *resolve_undo;
+       struct cache_tree *cache_tree;
+       struct split_index *split_index;
+       struct cache_time timestamp;
+       unsigned name_hash_initialized : 1,
+                initialized : 1,
+                drop_cache_tree : 1,
+                updated_workdir : 1,
+                updated_skipworktree : 1,
+                fsmonitor_has_run_once : 1;
+       enum sparse_index_mode sparse_index;
+       struct hashmap name_hash;
+       struct hashmap dir_hash;
+       struct object_id oid;
+       struct untracked_cache *untracked;
+       char *fsmonitor_last_update;
+       struct ewah_bitmap *fsmonitor_dirty;
+       struct mem_pool *ce_mem_pool;
+       struct progress *progress;
+       struct repository *repo;
+       struct pattern_list *sparse_checkout_patterns;
+};
+
+/**
+ * A "struct index_state istate" must be initialized with
+ * INDEX_STATE_INIT or the corresponding index_state_init().
+ *
+ * If the variable won't be used again, use release_index() to free()
+ * its resources. If it needs to be used again use discard_index(),
+ * which does the same thing, but will use use index_state_init() at
+ * the end. The discard_index() will use its own "istate->repo" as the
+ * "r" argument to index_state_init() in that case.
+ */
+#define INDEX_STATE_INIT(r) { \
+       .repo = (r), \
+}
+void index_state_init(struct index_state *istate, struct repository *r);
+void release_index(struct index_state *istate);
+
+/* Cache entry creation and cleanup */
+
+/*
+ * Create cache_entry intended for use in the specified index. Caller
+ * is responsible for discarding the cache_entry with
+ * `discard_cache_entry`.
+ */
+struct cache_entry *make_cache_entry(struct index_state *istate,
+                                    unsigned int mode,
+                                    const struct object_id *oid,
+                                    const char *path,
+                                    int stage,
+                                    unsigned int refresh_options);
+
+struct cache_entry *make_empty_cache_entry(struct index_state *istate,
+                                          size_t name_len);
+
+/*
+ * Create a cache_entry that is not intended to be added to an index. If
+ * `ce_mem_pool` is not NULL, the entry is allocated within the given memory
+ * pool. Caller is responsible for discarding "loose" entries with
+ * `discard_cache_entry()` and the memory pool with
+ * `mem_pool_discard(ce_mem_pool, should_validate_cache_entries())`.
+ */
+struct cache_entry *make_transient_cache_entry(unsigned int mode,
+                                              const struct object_id *oid,
+                                              const char *path,
+                                              int stage,
+                                              struct mem_pool *ce_mem_pool);
+
+struct cache_entry *make_empty_transient_cache_entry(size_t len,
+                                                    struct mem_pool *ce_mem_pool);
+
+/*
+ * Discard cache entry.
+ */
+void discard_cache_entry(struct cache_entry *ce);
+
+/*
+ * Check configuration if we should perform extra validation on cache
+ * entries.
+ */
+int should_validate_cache_entries(void);
+
+/*
+ * Duplicate a cache_entry. Allocate memory for the new entry from a
+ * memory_pool. Takes into account cache_entry fields that are meant
+ * for managing the underlying memory allocation of the cache_entry.
+ */
+struct cache_entry *dup_cache_entry(const struct cache_entry *ce, struct index_state *istate);
+
+/*
+ * Validate the cache entries in the index.  This is an internal
+ * consistency check that the cache_entry structs are allocated from
+ * the expected memory pool.
+ */
+void validate_cache_entries(const struct index_state *istate);
+
+/*
+ * Bulk prefetch all missing cache entries that are not GITLINKs and that match
+ * the given predicate. This function should only be called if
+ * repo_has_promisor_remote() returns true.
+ */
+typedef int (*must_prefetch_predicate)(const struct cache_entry *);
+void prefetch_cache_entries(const struct index_state *istate,
+                           must_prefetch_predicate must_prefetch);
+
+/* Initialize and use the cache information */
+struct lock_file;
+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 *);
+
+/* For use with `write_locked_index()`. */
+#define COMMIT_LOCK            (1 << 0)
+#define SKIP_IF_UNCHANGED      (1 << 1)
+
+/*
+ * Write the index while holding an already-taken lock. Close the lock,
+ * and if `COMMIT_LOCK` is given, commit it.
+ *
+ * Unless a split index is in use, write the index into the lockfile.
+ *
+ * With a split index, write the shared index to a temporary file,
+ * adjust its permissions and rename it into place, then write the
+ * split index to the lockfile. If the temporary file for the shared
+ * index cannot be created, fall back to the behavior described in
+ * the previous paragraph.
+ *
+ * With `COMMIT_LOCK`, the lock is always committed or rolled back.
+ * Without it, the lock is closed, but neither committed nor rolled
+ * back.
+ *
+ * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
+ * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
+ */
+int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
+
+void discard_index(struct index_state *);
+void move_index_extensions(struct index_state *dst, struct index_state *src);
+int unmerged_index(const struct index_state *);
+
+/**
+ * Returns 1 if istate differs from tree, 0 otherwise.  If tree is NULL,
+ * compares istate to HEAD.  If tree is NULL and on an unborn branch,
+ * returns 1 if there are entries in istate, 0 otherwise.  If an strbuf is
+ * provided, the space-separated list of files that differ will be appended
+ * to it.
+ */
+int repo_index_has_changes(struct repository *repo,
+                          struct tree *tree,
+                          struct strbuf *sb);
+
+int verify_path(const char *path, unsigned mode);
+int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
+
+/*
+ * Searches for an entry defined by name and namelen in the given index.
+ * If the return value is positive (including 0) it is the position of an
+ * exact match. If the return value is negative, the negated value minus 1
+ * is the position where the entry would be inserted.
+ * Example: The current index consists of these files and its stages:
+ *
+ *   b#0, d#0, f#1, f#3
+ *
+ * index_name_pos(&index, "a", 1) -> -1
+ * index_name_pos(&index, "b", 1) ->  0
+ * index_name_pos(&index, "c", 1) -> -2
+ * index_name_pos(&index, "d", 1) ->  1
+ * index_name_pos(&index, "e", 1) -> -3
+ * index_name_pos(&index, "f", 1) -> -3
+ * index_name_pos(&index, "g", 1) -> -5
+ */
+int index_name_pos(struct index_state *, const char *name, int namelen);
+
+/*
+ * Like index_name_pos, returns the position of an entry of the given name in
+ * the index if one exists, otherwise returns a negative value where the negated
+ * value minus 1 is the position where the index entry would be inserted. Unlike
+ * index_name_pos, however, a sparse index is not expanded to find an entry
+ * inside a sparse directory.
+ */
+int index_name_pos_sparse(struct index_state *, const char *name, int namelen);
+
+/*
+ * Determines whether an entry with the given name exists within the
+ * given index. The return value is 1 if an exact match is found, otherwise
+ * it is 0. Note that, unlike index_name_pos, this function does not expand
+ * the index if it is sparse. If an item exists within the full index but it
+ * is contained within a sparse directory (and not in the sparse index), 0 is
+ * returned.
+ */
+int index_entry_exists(struct index_state *, const char *name, int namelen);
+
+/*
+ * Some functions return the negative complement of an insert position when a
+ * precise match was not found but a position was found where the entry would
+ * need to be inserted. This helper protects that logic from any integer
+ * underflow.
+ */
+static inline int index_pos_to_insert_pos(uintmax_t pos)
+{
+       if (pos > INT_MAX)
+               die("overflow: -1 - %"PRIuMAX, pos);
+       return -1 - (int)pos;
+}
+
+#define ADD_CACHE_OK_TO_ADD 1          /* Ok to add */
+#define ADD_CACHE_OK_TO_REPLACE 2      /* Ok to replace file/directory */
+#define ADD_CACHE_SKIP_DFCHECK 4       /* Ok to skip DF conflict checks */
+#define ADD_CACHE_JUST_APPEND 8                /* Append only */
+#define ADD_CACHE_NEW_ONLY 16          /* Do not replace existing ones */
+#define ADD_CACHE_KEEP_CACHE_TREE 32   /* Do not invalidate cache-tree */
+#define ADD_CACHE_RENORMALIZE 64        /* Pass along HASH_RENORMALIZE */
+int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
+void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
+
+/* Remove entry, return true if there are more entries to go. */
+int remove_index_entry_at(struct index_state *, int pos);
+
+void remove_marked_cache_entries(struct index_state *istate, int invalidate);
+int remove_file_from_index(struct index_state *, const char *path);
+#define ADD_CACHE_VERBOSE 1
+#define ADD_CACHE_PRETEND 2
+#define ADD_CACHE_IGNORE_ERRORS        4
+#define ADD_CACHE_IGNORE_REMOVAL 8
+#define ADD_CACHE_INTENT 16
+/*
+ * These two are used to add the contents of the file at path
+ * to the index, marking the working tree up-to-date by storing
+ * the cached stat info in the resulting cache entry.  A caller
+ * that has already run lstat(2) on the path can call
+ * add_to_index(), and all others can call add_file_to_index();
+ * the latter will do necessary lstat(2) internally before
+ * calling the former.
+ */
+int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
+int add_file_to_index(struct index_state *, const char *path, int flags);
+
+int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
+int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
+void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
+int index_name_is_other(struct index_state *, const char *, int);
+void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
+
+/* do stat comparison even if CE_VALID is true */
+#define CE_MATCH_IGNORE_VALID          01
+/* do not check the contents but report dirty on racily-clean entries */
+#define CE_MATCH_RACY_IS_DIRTY         02
+/* do stat comparison even if CE_SKIP_WORKTREE is true */
+#define CE_MATCH_IGNORE_SKIP_WORKTREE  04
+/* ignore non-existent files during stat update  */
+#define CE_MATCH_IGNORE_MISSING                0x08
+/* enable stat refresh */
+#define CE_MATCH_REFRESH               0x10
+/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
+#define CE_MATCH_IGNORE_FSMONITOR 0X20
+int is_racy_timestamp(const struct index_state *istate,
+                     const struct cache_entry *ce);
+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);
+
+int match_stat_data_racy(const struct index_state *istate,
+                        const struct stat_data *sd, struct stat *st);
+
+void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st);
+
+#define REFRESH_REALLY                   (1 << 0) /* ignore_valid */
+#define REFRESH_UNMERGED                 (1 << 1) /* allow unmerged */
+#define REFRESH_QUIET                    (1 << 2) /* be quiet about it */
+#define REFRESH_IGNORE_MISSING           (1 << 3) /* ignore non-existent */
+#define REFRESH_IGNORE_SUBMODULES        (1 << 4) /* ignore submodules */
+#define REFRESH_IN_PORCELAIN             (1 << 5) /* user friendly output, not "needs update" */
+#define REFRESH_PROGRESS                 (1 << 6) /* show progress bar if stderr is tty */
+#define REFRESH_IGNORE_SKIP_WORKTREE     (1 << 7) /* ignore skip_worktree entries */
+int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
+/*
+ * Refresh the index and write it to disk.
+ *
+ * 'refresh_flags' is passed directly to 'refresh_index()', while
+ * 'COMMIT_LOCK | write_flags' is passed to 'write_locked_index()', so
+ * the lockfile is always either committed or rolled back.
+ *
+ * If 'gentle' is passed, errors locking the index are ignored.
+ *
+ * Return 1 if refreshing the index returns an error, -1 if writing
+ * the index to disk fails, 0 on success.
+ *
+ * Note that if refreshing the index returns an error, we still write
+ * out the index (unless locking fails).
+ */
+int repo_refresh_and_write_index(struct repository*, unsigned int refresh_flags, unsigned int write_flags, int gentle, const struct pathspec *, char *seen, const char *header_msg);
+
+struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
+
+void set_alternate_index_output(const char *);
+
+extern int verify_index_checksum;
+extern int verify_ce_order;
+
+int cmp_cache_name_compare(const void *a_, const void *b_);
+
+int add_files_to_cache(struct repository *repo, const char *prefix,
+                      const struct pathspec *pathspec, int include_sparse,
+                      int flags);
+
+void overlay_tree_on_index(struct index_state *istate,
+                          const char *tree_name, const char *prefix);
+
+#endif /* READ_CACHE_LL_H */
index 35e5657877c7a4ebd070654f7b252a99f05d702f..080bd39713bc1782434b7212954e6bc590fa4d6d 100644 (file)
@@ -3,24 +3,40 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "bulk-checkin.h"
 #include "config.h"
+#include "date.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "hex.h"
 #include "tempfile.h"
 #include "lockfile.h"
 #include "cache-tree.h"
 #include "refs.h"
 #include "dir.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
 #include "tree.h"
 #include "commit.h"
 #include "blob.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"
 #include "varint.h"
 #include "split-index.h"
+#include "symlinks.h"
 #include "utf8.h"
 #include "fsmonitor.h"
 #include "thread-utils.h"
@@ -163,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
@@ -263,7 +224,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)
        if (strbuf_readlink(&sb, ce->name, expected_size))
                return -1;
 
-       buffer = read_object_file(&ce->oid, &type, &size);
+       buffer = repo_read_object_file(the_repository, &ce->oid, &type, &size);
        if (buffer) {
                if (size == sb.len)
                        match = memcmp(buffer, sb.buf, size);
@@ -488,87 +449,30 @@ int ie_modified(struct index_state *istate,
        return 0;
 }
 
-int base_name_compare(const char *name1, size_t len1, int mode1,
-                     const char *name2, size_t len2, int mode2)
+static int cache_name_stage_compare(const char *name1, int len1, int stage1,
+                                   const char *name2, int len2, int stage2)
 {
-       unsigned char c1, c2;
-       size_t len = len1 < len2 ? len1 : len2;
        int cmp;
 
-       cmp = memcmp(name1, name2, len);
-       if (cmp)
-               return cmp;
-       c1 = name1[len];
-       c2 = name2[len];
-       if (!c1 && S_ISDIR(mode1))
-               c1 = '/';
-       if (!c2 && S_ISDIR(mode2))
-               c2 = '/';
-       return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
-}
-
-/*
- * df_name_compare() is identical to base_name_compare(), except it
- * compares conflicting directory/file entries as equal. Note that
- * while a directory name compares as equal to a regular file, they
- * then individually compare _differently_ to a filename that has
- * a dot after the basename (because '\0' < '.' < '/').
- *
- * This is used by routines that want to traverse the git namespace
- * but then handle conflicting entries together when possible.
- */
-int df_name_compare(const char *name1, size_t len1, int mode1,
-                   const char *name2, size_t len2, int mode2)
-{
-       unsigned char c1, c2;
-       size_t len = len1 < len2 ? len1 : len2;
-       int cmp;
-
-       cmp = memcmp(name1, name2, len);
+       cmp = name_compare(name1, len1, name2, len2);
        if (cmp)
                return cmp;
-       /* Directories and files compare equal (same length, same name) */
-       if (len1 == len2)
-               return 0;
-       c1 = name1[len];
-       if (!c1 && S_ISDIR(mode1))
-               c1 = '/';
-       c2 = name2[len];
-       if (!c2 && S_ISDIR(mode2))
-               c2 = '/';
-       if (c1 == '/' && !c2)
-               return 0;
-       if (c2 == '/' && !c1)
-               return 0;
-       return c1 - c2;
-}
 
-int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
-{
-       size_t min_len = (len1 < len2) ? len1 : len2;
-       int cmp = memcmp(name1, name2, min_len);
-       if (cmp)
-               return cmp;
-       if (len1 < len2)
+       if (stage1 < stage2)
                return -1;
-       if (len1 > len2)
+       if (stage1 > stage2)
                return 1;
        return 0;
 }
 
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
+int cmp_cache_name_compare(const void *a_, const void *b_)
 {
-       int cmp;
-
-       cmp = name_compare(name1, len1, name2, len2);
-       if (cmp)
-               return cmp;
+       const struct cache_entry *ce1, *ce2;
 
-       if (stage1 < stage2)
-               return -1;
-       if (stage1 > stage2)
-               return 1;
-       return 0;
+       ce1 = *((const struct cache_entry **)a_);
+       ce2 = *((const struct cache_entry **)b_);
+       return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
+                                 ce2->name, ce2->ce_namelen, ce_stage(ce2));
 }
 
 static int index_name_stage_pos(struct index_state *istate,
@@ -2330,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);
@@ -2499,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);
@@ -2628,7 +2535,7 @@ int repo_index_has_changes(struct repository *repo,
 
        if (tree)
                cmp = tree->object.oid;
-       if (tree || !get_oid_tree("HEAD", &cmp)) {
+       if (tree || !repo_get_oid_tree(repo, "HEAD", &cmp)) {
                struct diff_options opt;
 
                repo_diff_setup(repo, &opt);
@@ -2901,6 +2808,16 @@ static int record_ieot(void)
        return !git_config_get_index_threads(&val) && val != 1;
 }
 
+enum write_extensions {
+       WRITE_NO_EXTENSION =              0,
+       WRITE_SPLIT_INDEX_EXTENSION =     1<<0,
+       WRITE_CACHE_TREE_EXTENSION =      1<<1,
+       WRITE_RESOLVE_UNDO_EXTENSION =    1<<2,
+       WRITE_UNTRACKED_CACHE_EXTENSION = 1<<3,
+       WRITE_FSMONITOR_EXTENSION =       1<<4,
+};
+#define WRITE_ALL_EXTENSIONS ((enum write_extensions)-1)
+
 /*
  * On success, `tempfile` is closed. If it is the temporary file
  * of a `struct lock_file`, we will therefore effectively perform
@@ -2909,7 +2826,7 @@ static int record_ieot(void)
  * rely on it.
  */
 static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
-                         int strip_extensions, unsigned flags)
+                         enum write_extensions write_extensions, unsigned flags)
 {
        uint64_t start = getnanotime();
        struct hashfile *f;
@@ -2947,7 +2864,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        }
 
        if (!istate->version)
-               istate->version = get_index_format_default(the_repository);
+               istate->version = get_index_format_default(r);
 
        /* demote version 3 to version 2 when the latter suffices */
        if (istate->version == 3 || istate->version == 2)
@@ -3082,8 +2999,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                        return -1;
        }
 
-       if (!strip_extensions && istate->split_index &&
-           !is_null_oid(&istate->split_index->base_oid)) {
+       if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
+           istate->split_index) {
                struct strbuf sb = STRBUF_INIT;
 
                if (istate->sparse_index)
@@ -3097,7 +3014,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                if (err)
                        return -1;
        }
-       if (!strip_extensions && !drop_cache_tree && istate->cache_tree) {
+       if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
+           !drop_cache_tree && istate->cache_tree) {
                struct strbuf sb = STRBUF_INIT;
 
                cache_tree_write(&sb, istate->cache_tree);
@@ -3107,7 +3025,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                if (err)
                        return -1;
        }
-       if (!strip_extensions && istate->resolve_undo) {
+       if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
+           istate->resolve_undo) {
                struct strbuf sb = STRBUF_INIT;
 
                resolve_undo_write(&sb, istate->resolve_undo);
@@ -3118,7 +3037,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                if (err)
                        return -1;
        }
-       if (!strip_extensions && istate->untracked) {
+       if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
+           istate->untracked) {
                struct strbuf sb = STRBUF_INIT;
 
                write_untracked_extension(&sb, istate->untracked);
@@ -3129,7 +3049,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                if (err)
                        return -1;
        }
-       if (!strip_extensions && istate->fsmonitor_last_update) {
+       if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
+           istate->fsmonitor_last_update) {
                struct strbuf sb = STRBUF_INIT;
 
                write_fsmonitor_extension(&sb, istate);
@@ -3203,8 +3124,10 @@ static int commit_locked_index(struct lock_file *lk)
                return commit_lock_file(lk);
 }
 
-static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
-                                unsigned flags)
+static int do_write_locked_index(struct index_state *istate,
+                                struct lock_file *lock,
+                                unsigned flags,
+                                enum write_extensions write_extensions)
 {
        int ret;
        int was_full = istate->sparse_index == INDEX_EXPANDED;
@@ -3222,7 +3145,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
         */
        trace2_region_enter_printf("index", "do_write_index", the_repository,
                                   "%s", get_lock_file_path(lock));
-       ret = do_write_index(istate, lock->tempfile, 0, flags);
+       ret = do_write_index(istate, lock->tempfile, write_extensions, flags);
        trace2_region_leave_printf("index", "do_write_index", the_repository,
                                   "%s", get_lock_file_path(lock));
 
@@ -3251,7 +3174,7 @@ static int write_split_index(struct index_state *istate,
 {
        int ret;
        prepare_to_write_split_index(istate);
-       ret = do_write_locked_index(istate, lock, flags);
+       ret = do_write_locked_index(istate, lock, flags, WRITE_ALL_EXTENSIONS);
        finish_writing_split_index(istate);
        return ret;
 }
@@ -3326,7 +3249,7 @@ static int write_shared_index(struct index_state *istate,
 
        trace2_region_enter_printf("index", "shared/do_write_index",
                                   the_repository, "%s", get_tempfile_path(*temp));
-       ret = do_write_index(si->base, *temp, 1, flags);
+       ret = do_write_index(si->base, *temp, WRITE_NO_EXTENSION, flags);
        trace2_region_leave_printf("index", "shared/do_write_index",
                                   the_repository, "%s", get_tempfile_path(*temp));
 
@@ -3403,9 +3326,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
        if ((!si && !test_split_index_env) ||
            alternate_index_output ||
            (istate->cache_changed & ~EXTMASK)) {
-               if (si)
-                       oidclr(&si->base_oid);
-               ret = do_write_locked_index(istate, lock, flags);
+               ret = do_write_locked_index(istate, lock, flags,
+                                           ~WRITE_SPLIT_INDEX_EXTENSION);
                goto out;
        }
 
@@ -3431,8 +3353,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
                /* Same initial permissions as the main .git/index file */
                temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
                if (!temp) {
-                       oidclr(&si->base_oid);
-                       ret = do_write_locked_index(istate, lock, flags);
+                       ret = do_write_locked_index(istate, lock, flags,
+                                                   ~WRITE_SPLIT_INDEX_EXTENSION);
                        goto out;
                }
                ret = write_shared_index(istate, &temp, flags);
@@ -3553,7 +3475,8 @@ void *read_blob_data_from_index(struct index_state *istate,
        }
        if (pos < 0)
                return NULL;
-       data = read_object_file(&istate->cache[pos]->oid, &type, &sz);
+       data = repo_read_object_file(the_repository, &istate->cache[pos]->oid,
+                                    &type, &sz);
        if (!data || type != OBJ_BLOB) {
                free(data);
                return NULL;
@@ -3563,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;
@@ -3835,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 7407c593191679c757573e567a28f35c65c9cb33..d9718409b3d7862fee0eaa7e2255e83f50379656 100644 (file)
@@ -1,11 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "commit.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
 #include "sequencer.h"
 #include "rebase-interactive.h"
+#include "repository.h"
 #include "strbuf.h"
 #include "commit-slab.h"
 #include "config.h"
 #include "dir.h"
+#include "object-name.h"
 
 static const char edit_todo_list_advice[] =
 N_("You can fix this with 'git rebase --edit-todo' "
@@ -66,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' "
@@ -81,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 "
@@ -92,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,
@@ -124,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;
 
@@ -187,7 +193,7 @@ int todo_list_check(struct todo_list *old_todo, struct todo_list *new_todo)
                struct commit *commit = item->commit;
                if (commit && !*commit_seen_at(&commit_seen, commit)) {
                        strbuf_addf(&missing, " - %s %.*s\n",
-                                   find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV),
+                                   repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
                                    item->arg_len,
                                    todo_item_get_arg(old_todo, item));
                        *commit_seen_at(&commit_seen, commit) = 1;
index 6775cddb28434d0780cb483357476f4783e1f596..17a570f1ff97fab8e789d2960ae54894b1c42a80 100644 (file)
--- a/rebase.c
+++ b/rebase.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "rebase.h"
 #include "config.h"
 #include "gettext.h"
index f8203c6b05254b624cf98e6d4590d07064cbb101..9dbc4f71bd272a25423f131bbbbb23152a248be8 100644 (file)
@@ -1,9 +1,16 @@
-#include "builtin.h"
-#include "cache.h"
+#include "git-compat-util.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-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
 #include "repository.h"
 #include "commit.h"
 #include "remote.h"
@@ -13,8 +20,8 @@
 #include "ref-filter.h"
 #include "revision.h"
 #include "utf8.h"
-#include "git-compat-util.h"
 #include "version.h"
+#include "versioncmp.h"
 #include "trailer.h"
 #include "wt-status.h"
 #include "commit-slab.h"
@@ -140,10 +147,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,
@@ -158,6 +167,7 @@ enum atom_type {
        ATOM_THEN,
        ATOM_ELSE,
        ATOM_REST,
+       ATOM_AHEADBEHIND,
 };
 
 /*
@@ -208,6 +218,11 @@ static struct used_atom {
                struct email_option {
                        enum { EO_RAW, EO_TRIM, EO_LOCALPART } 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;
@@ -244,6 +259,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)
 {
@@ -282,7 +401,8 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
        return 0;
 }
 
-static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int remote_ref_atom_parser(struct ref_format *format UNUSED,
+                                 struct used_atom *atom,
                                  const char *arg, struct strbuf *err)
 {
        struct string_list params = STRING_LIST_INIT_DUP;
@@ -329,7 +449,8 @@ static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *a
        return 0;
 }
 
-static int objecttype_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int objecttype_atom_parser(struct ref_format *format UNUSED,
+                                 struct used_atom *atom,
                                  const char *arg, struct strbuf *err)
 {
        if (arg)
@@ -341,7 +462,8 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a
        return 0;
 }
 
-static int objectsize_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int objectsize_atom_parser(struct ref_format *format UNUSED,
+                                 struct used_atom *atom,
                                  const char *arg, struct strbuf *err)
 {
        if (!arg) {
@@ -361,7 +483,8 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a
        return 0;
 }
 
-static int deltabase_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int deltabase_atom_parser(struct ref_format *format UNUSED,
+                                struct used_atom *atom,
                                 const char *arg, struct strbuf *err)
 {
        if (arg)
@@ -373,7 +496,8 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at
        return 0;
 }
 
-static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int body_atom_parser(struct ref_format *format UNUSED,
+                           struct used_atom *atom,
                            const char *arg, struct strbuf *err)
 {
        if (arg)
@@ -382,7 +506,8 @@ static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
        return 0;
 }
 
-static int subject_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int subject_atom_parser(struct ref_format *format UNUSED,
+                              struct used_atom *atom,
                               const char *arg, struct strbuf *err)
 {
        if (!arg)
@@ -394,6 +519,36 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom
        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, struct used_atom *atom,
                                const char *arg, struct strbuf *err)
 {
@@ -427,9 +582,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;
@@ -448,19 +604,103 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
        return 0;
 }
 
-static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
+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;
 }
 
-static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int oid_atom_parser(struct ref_format *format UNUSED,
+                          struct used_atom *atom,
                           const char *arg, struct strbuf *err)
 {
        if (!arg)
@@ -479,7 +719,8 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
        return 0;
 }
 
-static int person_email_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int person_email_atom_parser(struct ref_format *format UNUSED,
+                                   struct used_atom *atom,
                                    const char *arg, struct strbuf *err)
 {
        if (!arg)
@@ -493,7 +734,8 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom
        return 0;
 }
 
-static int refname_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int refname_atom_parser(struct ref_format *format UNUSED,
+                              struct used_atom *atom,
                               const char *arg, struct strbuf *err)
 {
        return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err);
@@ -510,7 +752,8 @@ static align_type parse_align_position(const char *s)
        return -1;
 }
 
-static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int align_atom_parser(struct ref_format *format UNUSED,
+                            struct used_atom *atom,
                             const char *arg, struct strbuf *err)
 {
        struct align *align = &atom->u.align;
@@ -562,7 +805,8 @@ static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
        return 0;
 }
 
-static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int if_atom_parser(struct ref_format *format UNUSED,
+                         struct used_atom *atom,
                          const char *arg, struct strbuf *err)
 {
        if (!arg) {
@@ -577,16 +821,33 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
        return 0;
 }
 
-static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int rest_atom_parser(struct ref_format *format,
+                           struct used_atom *atom UNUSED,
                            const char *arg, struct strbuf *err)
 {
        if (arg)
                return err_no_arg(err, "rest");
-       format->use_rest = 1;
        return 0;
 }
 
-static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom *atom,
+                                   const char *arg, struct strbuf *err)
+{
+       struct string_list_item *item;
+
+       if (!arg)
+               return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
+
+       item = string_list_append(&format->bases, arg);
+       item->util = lookup_commit_reference_by_name(arg);
+       if (!item->util)
+               die("failed to find '%s'", arg);
+
+       return 0;
+}
+
+static int head_atom_parser(struct ref_format *format UNUSED,
+                           struct used_atom *atom,
                            const char *arg, struct strbuf *err)
 {
        if (arg)
@@ -627,10 +888,12 @@ static struct {
        [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 },
@@ -645,6 +908,7 @@ static struct {
        [ATOM_THEN] = { "then", SOURCE_NONE },
        [ATOM_ELSE] = { "else", SOURCE_NONE },
        [ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser },
+       [ATOM_AHEADBEHIND] = { "ahead-behind", SOURCE_OTHER, FIELD_STR, ahead_behind_atom_parser },
        /*
         * Please update $__git_ref_fieldlist in git-completion.bash
         * when you add new atoms
@@ -791,7 +1055,7 @@ static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int
 }
 
 static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
-                      struct strbuf *unused_err)
+                      struct strbuf *err UNUSED)
 {
        /*
         * Quote formatting is only done when the stack has a single
@@ -841,7 +1105,7 @@ static void end_align_handler(struct ref_formatting_stack **stack)
 }
 
 static int align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
-                             struct strbuf *unused_err)
+                             struct strbuf *err UNUSED)
 {
        struct ref_formatting_stack *new_stack;
 
@@ -888,7 +1152,7 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
 }
 
 static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
-                          struct strbuf *unused_err)
+                          struct strbuf *err UNUSED)
 {
        struct ref_formatting_stack *new_stack;
        struct if_then_else *if_then_else = xcalloc(1,
@@ -915,7 +1179,8 @@ static int is_empty(struct strbuf *buf)
        return cur == end;
  }
 
-static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int then_atom_handler(struct atom_value *atomv UNUSED,
+                            struct ref_formatting_state *state,
                             struct strbuf *err)
 {
        struct ref_formatting_stack *cur = state->stack;
@@ -952,7 +1217,8 @@ static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
        return 0;
 }
 
-static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int else_atom_handler(struct atom_value *atomv UNUSED,
+                            struct ref_formatting_state *state,
                             struct strbuf *err)
 {
        struct ref_formatting_stack *prev = state->stack;
@@ -973,7 +1239,8 @@ static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
        return 0;
 }
 
-static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int end_atom_handler(struct atom_value *atomv UNUSED,
+                           struct ref_formatting_state *state,
                            struct strbuf *err)
 {
        struct ref_formatting_stack *current = state->stack;
@@ -1075,9 +1342,11 @@ static const char *do_grab_oid(const char *field, const struct object_id *oid,
        case O_FULL:
                return oid_to_hex(oid);
        case O_LENGTH:
-               return find_unique_abbrev(oid, atom->u.oid.length);
+               return repo_find_unique_abbrev(the_repository, oid,
+                                              atom->u.oid.length);
        case O_SHORT:
-               return find_unique_abbrev(oid, DEFAULT_ABBREV);
+               return repo_find_unique_abbrev(the_repository, oid,
+                                              DEFAULT_ABBREV);
        default:
                BUG("unknown %%(%s) option", field);
        }
@@ -1362,6 +1631,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,
@@ -1440,6 +1795,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)
 {
@@ -1466,7 +1859,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;
                }
@@ -1492,9 +1886,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);
@@ -1549,12 +1944,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); */
@@ -1822,7 +2220,7 @@ static void lazy_init_worktree_map(void)
        populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
 }
 
-static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+static char *get_worktree_path(const struct ref_array_item *ref)
 {
        struct hashmap_entry entry, *e;
        struct ref_to_worktree_entry *lookup_result;
@@ -1848,6 +2246,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
        struct object *obj;
        int i;
        struct object_info empty = OBJECT_INFO_INIT;
+       int ahead_behind_atoms = 0;
 
        CALLOC_ARRAY(ref->value, used_atom_cnt);
 
@@ -1870,6 +2269,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 == '*') {
@@ -1881,7 +2281,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
                        refname = get_refname(atom, ref);
                else if (atom_type == ATOM_WORKTREEPATH) {
                        if (ref->kind == FILTER_REFS_BRANCHES)
-                               v->s = get_worktree_path(atom, ref);
+                               v->s = get_worktree_path(ref);
                        else
                                v->s = xstrdup("");
                        continue;
@@ -1978,6 +2378,16 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
                        else
                                v->s = xstrdup("");
                        continue;
+               } else if (atom_type == ATOM_AHEADBEHIND) {
+                       if (ref->counts) {
+                               const struct ahead_behind_count *count;
+                               count = ref->counts[ahead_behind_atoms++];
+                               v->s = xstrfmt("%d %d", count->ahead, count->behind);
+                       } else {
+                               /* Not a commit. */
+                               v->s = xstrdup("");
+                       }
+                       continue;
                } else
                        continue;
 
@@ -2050,12 +2460,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;
 
        /*
@@ -2080,13 +2490,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++) {
@@ -2111,8 +2521,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);
 }
 
 /*
@@ -2144,43 +2566,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;
 }
 
 /*
@@ -2282,6 +2714,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;
 
@@ -2328,6 +2763,7 @@ static void free_array_item(struct ref_array_item *item)
                        free((char *)item->value[i].s);
                free(item->value);
        }
+       free(item->counts);
        free(item);
 }
 
@@ -2356,41 +2792,32 @@ void ref_array_clear(struct ref_array *array)
                free_worktrees(ref_to_worktree_map.worktrees);
                ref_to_worktree_map.worktrees = NULL;
        }
+
+       FREE_AND_NULL(array->counts);
 }
 
 #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)
 {
-       struct rev_info revs;
        int i, old_nr;
        struct commit **to_clear;
-       struct commit_list *cr;
 
-       if (!check_reachable)
+       if (!*check_reachable)
                return;
 
        CALLOC_ARRAY(to_clear, array->nr);
-
-       repo_init_revisions(the_repository, &revs, NULL);
-
        for (i = 0; i < array->nr; i++) {
                struct ref_array_item *item = array->items[i];
-               add_pending_object(&revs, &item->commit->object, item->refname);
                to_clear[i] = item->commit;
        }
 
-       for (cr = check_reachable; cr; cr = cr->next) {
-               struct commit *merge_commit = cr->item;
-               merge_commit->object.flags |= UNINTERESTING;
-               add_pending_object(&revs, &merge_commit->object, "");
-       }
-
-       revs.limited = 1;
-       if (prepare_revision_walk(&revs))
-               die(_("revision walk setup failed"));
+       tips_reachable_from_bases(the_repository,
+                                 *check_reachable,
+                                 to_clear, array->nr,
+                                 UNINTERESTING);
 
        old_nr = array->nr;
        array->nr = 0;
@@ -2409,15 +2836,55 @@ 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);
        }
 
-       release_revisions(&revs);
        free(to_clear);
 }
 
+void filter_ahead_behind(struct repository *r,
+                        struct ref_format *format,
+                        struct ref_array *array)
+{
+       struct commit **commits;
+       size_t commits_nr = format->bases.nr + array->nr;
+
+       if (!format->bases.nr || !array->nr)
+               return;
+
+       ALLOC_ARRAY(commits, commits_nr);
+       for (size_t i = 0; i < format->bases.nr; i++)
+               commits[i] = format->bases.items[i].util;
+
+       ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
+
+       commits_nr = format->bases.nr;
+       array->counts_nr = 0;
+       for (size_t i = 0; i < array->nr; i++) {
+               const char *name = array->items[i]->refname;
+               commits[commits_nr] = lookup_commit_reference_by_name(name);
+
+               if (!commits[commits_nr])
+                       continue;
+
+               CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
+               for (size_t j = 0; j < format->bases.nr; j++) {
+                       struct ahead_behind_count *count;
+                       count = &array->counts[array->counts_nr++];
+                       count->tip_index = commits_nr;
+                       count->base_index = j;
+
+                       array->items[i]->counts[j] = count;
+               }
+               commits_nr++;
+       }
+
+       ahead_behind(r, commits, commits_nr, array->counts, array->counts_nr);
+       free(commits);
+}
+
 /*
  * API for filtering a set of refs. Based on the type of refs the user
  * has requested, we iterate through those refs and apply filters
@@ -2467,8 +2934,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;
@@ -2765,7 +3232,7 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
 
        BUG_ON_OPT_NEG(unset);
 
-       if (get_oid(arg, &oid))
+       if (repo_get_oid(the_repository, arg, &oid))
                die(_("malformed object name %s"), arg);
 
        merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0);
@@ -2780,3 +3247,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 aa0eea4ecf591edd0620dc47db0e0bfc3e5c4208..1524bc463a5701d475cb68e50caa884a6daf890a 100644 (file)
@@ -1,10 +1,12 @@
 #ifndef REF_FILTER_H
 #define REF_FILTER_H
 
+#include "gettext.h"
 #include "oid-array.h"
 #include "refs.h"
 #include "commit.h"
-#include "parse-options.h"
+#include "string-list.h"
+#include "strvec.h"
 
 /* Quoting styles */
 #define QUOTE_NONE 0
@@ -24,6 +26,8 @@
 
 struct atom_value;
 struct ref_sorting;
+struct ahead_behind_count;
+struct option;
 
 enum ref_sorting_order {
        REF_SORTING_REVERSE = 1<<0,
@@ -40,6 +44,8 @@ struct ref_array_item {
        const char *symref;
        struct commit *commit;
        struct atom_value *value;
+       struct ahead_behind_count **counts;
+
        char refname[FLEX_ARRAY];
 };
 
@@ -47,10 +53,14 @@ struct ref_array {
        int nr, alloc;
        struct ref_array_item **items;
        struct rev_info *revs;
+
+       struct ahead_behind_count *counts;
+       size_t counts_nr;
 };
 
 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;
@@ -75,14 +85,23 @@ struct ref_format {
        const char *format;
        const char *rest;
        int quote_style;
-       int use_rest;
        int use_color;
 
        /* Internal state to ref-filter */
        int need_color_reset_at_eol;
+
+       /* List of bases for ahead-behind counts. */
+       struct string_list bases;
 };
 
-#define REF_FORMAT_INIT { .use_color = -1 }
+#define REF_FILTER_INIT { \
+       .points_at = OID_ARRAY_INIT, \
+       .exclude = STRVEC_INIT, \
+}
+#define REF_FORMAT_INIT {             \
+       .use_color = -1,              \
+       .bases = STRING_LIST_INIT_DUP, \
+}
 
 /*  Macros for checking --merged and --no-merged options */
 #define _OPT_MERGED_NO_MERGED(option, filter, h) \
@@ -96,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
@@ -143,4 +165,18 @@ struct ref_array_item *ref_array_push(struct ref_array *array,
                                      const char *refname,
                                      const struct object_id *oid);
 
+/*
+ * If the provided format includes ahead-behind atoms, then compute the
+ * ahead-behind values for the array of filtered references. Must be
+ * called after filter_refs() but before outputting the formatted refs.
+ *
+ * If this is not called, then any ahead-behind atoms will be blank.
+ */
+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 8a4d8fa3bd5589fca43e97b05982a830af8bd27a..d216f6f966da91459ea946790be56ba011760170 100644 (file)
@@ -1,7 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.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 8076f10d9fbc0dd5588582f5bfec105416037233..4d93a269571980772c49cb25d37749a033482b4f 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef REFLOG_WALK_H
 #define REFLOG_WALK_H
 
-#include "cache.h"
-
 struct commit;
 struct reflog_walk_info;
 struct date_mode;
index 04630f56ec6b3661ecb027fa0a8a5f49155bb3da..9ad50e7d93e40c7a5f9c7ad0cecb0b7d1766105b 100644 (file)
--- a/reflog.c
+++ b/reflog.c
@@ -1,8 +1,11 @@
-#include "cache.h"
-#include "object-store.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "object-store-ll.h"
 #include "reflog.h"
 #include "refs.h"
 #include "revision.h"
+#include "tree.h"
+#include "tree-walk.h"
 #include "worktree.h"
 
 /* Remember to update object flag allocation in object.h */
@@ -28,7 +31,8 @@ static int tree_is_complete(const struct object_id *oid)
        if (!tree->buffer) {
                enum object_type type;
                unsigned long size;
-               void *data = read_object_file(oid, &type, &size);
+               void *data = repo_read_object_file(the_repository, oid, &type,
+                                                  &size);
                if (!data) {
                        tree->object.flags |= INCOMPLETE;
                        return 0;
@@ -39,7 +43,7 @@ static int tree_is_complete(const struct object_id *oid)
        init_tree_desc(&desc, tree->buffer, tree->size);
        complete = 1;
        while (tree_entry(&desc, &entry)) {
-               if (!has_object_file(&entry.oid) ||
+               if (!repo_has_object_file(the_repository, &entry.oid) ||
                    (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
                        tree->object.flags |= INCOMPLETE;
                        complete = 0;
@@ -186,7 +190,7 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb)
                struct commit *commit = pop_commit(&pending);
                if (commit->object.flags & REACHABLE)
                        continue;
-               if (parse_commit(commit))
+               if (repo_parse_commit(the_repository, commit))
                        continue;
                commit->object.flags |= REACHABLE;
                if (commit->date < expire_limit) {
diff --git a/refs.c b/refs.c
index aeae31c972f8c88084cc3d052329a3e23e60f1d4..fcae5dddc6050627668048e966384b7f9fa70171 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -2,25 +2,33 @@
  * The backend-independent part of the reference module.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "config.h"
+#include "environment.h"
 #include "hashmap.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "iterator.h"
 #include "refs.h"
 #include "refs/refs-internal.h"
 #include "run-command.h"
 #include "hook.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "object.h"
+#include "path.h"
 #include "tag.h"
 #include "submodule.h"
 #include "worktree.h"
 #include "strvec.h"
 #include "repository.h"
+#include "setup.h"
 #include "sigchain.h"
 #include "date.h"
 #include "commit.h"
+#include "wildmatch.h"
 
 /*
  * List of all available backends
@@ -367,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;
@@ -401,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;
@@ -561,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/"))
@@ -581,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;
@@ -1418,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) ||
@@ -1429,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;
@@ -1470,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)
@@ -1517,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;
@@ -1533,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:
@@ -1568,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);
 }
@@ -1578,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,
@@ -1590,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)
 {
@@ -1599,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);
@@ -1607,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)
@@ -1618,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)
@@ -1629,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)
@@ -1646,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);
 }
 
@@ -1729,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;
@@ -1744,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);
@@ -1821,7 +1862,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
                        return NULL;
 
                /*
-                * dwim_ref() uses REF_ISBROKEN to distinguish between
+                * repo_dwim_ref() uses REF_ISBROKEN to distinguish between
                 * missing refs and refs that were present but invalid,
                 * to complain about the latter to stderr.
                 *
@@ -2124,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)
@@ -2399,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 935cdd1ece3db3af483cb2225f204966c0e6cfa5..23211a5ea1cabbb0a35d091bf2b5dbbd87e28252 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -1,7 +1,6 @@
 #ifndef REFS_H
 #define REFS_H
 
-#include "cache.h"
 #include "commit.h"
 
 struct object_id;
@@ -64,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,
@@ -159,12 +164,6 @@ int expand_ref(struct repository *r, const char *str, int len, struct object_id
 int repo_dwim_ref(struct repository *r, const char *str, int len,
                  struct object_id *oid, char **ref, int nonfatal_dangling_mark);
 int repo_dwim_log(struct repository *r, const char *str, int len, struct object_id *oid, char **ref);
-static inline int dwim_ref(const char *str, int len, struct object_id *oid,
-                          char **ref, int nonfatal_dangling_mark)
-{
-       return repo_dwim_ref(the_repository, str, len, oid, ref,
-                            nonfatal_dangling_mark);
-}
 int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
 
 /*
@@ -344,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);
 
@@ -352,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);
 
 /**
@@ -373,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);
@@ -412,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.
@@ -811,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
@@ -821,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 eed8bc94b04f68125bb84eddfc26381ad86d3157..b7ffc4ce67e333321036592b7e53efa30f8871d8 100644 (file)
@@ -1,5 +1,7 @@
-
+#include "git-compat-util.h"
+#include "hex.h"
 #include "refs-internal.h"
+#include "string-list.h"
 #include "trace.h"
 
 static struct trace_key trace_refs = TRACE_KEY_INIT(REFS);
@@ -121,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;
 }
@@ -227,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 b89954355debd64056e045a5f433647ca8ba0160..341354182bbf10937dffc9de2c56645027f5cfcd 100644 (file)
@@ -1,16 +1,29 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
 #include "../config.h"
+#include "../copy.h"
+#include "../environment.h"
+#include "../gettext.h"
+#include "../hash.h"
+#include "../hex.h"
 #include "../refs.h"
 #include "refs-internal.h"
 #include "ref-cache.h"
 #include "packed-backend.h"
+#include "../ident.h"
 #include "../iterator.h"
 #include "../dir-iterator.h"
 #include "../lockfile.h"
 #include "../object.h"
+#include "../object-file.h"
+#include "../path.h"
 #include "../dir.h"
 #include "../chdir-notify.h"
-#include "worktree.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
@@ -819,7 +832,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;
@@ -864,7 +878,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);
@@ -1165,17 +1179,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;
@@ -1184,10 +1196,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,
@@ -1212,8 +1232,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;
 
                /*
@@ -1227,7 +1246,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 c9fd0bcaf90c753031a1624f593c607a4549bf5a..6b680f610efbee4e144cfa41763f45834b39d210 100644 (file)
@@ -3,7 +3,7 @@
  * documentation about the design and use of reference iterators.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "refs.h"
 #include "refs/refs-internal.h"
 #include "iterator.h"
index 6f5a0709fba65e80081fdb04563019e1f1e15400..59c78d7941f8d5e05fec6c895aafeb41803b919d 100644 (file)
@@ -1,11 +1,19 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
+#include "../alloc.h"
 #include "../config.h"
+#include "../gettext.h"
+#include "../hash.h"
+#include "../hex.h"
 #include "../refs.h"
 #include "refs-internal.h"
 #include "packed-backend.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 {
        /*
@@ -297,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;
@@ -306,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++;
@@ -521,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
@@ -566,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) {
@@ -582,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
@@ -646,7 +677,7 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
                                         snapshot->buf,
                                         snapshot->eof - snapshot->buf);
 
-               string_list_split_in_place(&traits, p, ' ', -1);
+               string_list_split_in_place(&traits, p, " ", -1);
 
                if (unsorted_string_list_has_string(&traits, "fully-peeled"))
                        snapshot->peeled = PEELED_FULLY;
@@ -773,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;
@@ -790,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) ||
@@ -905,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;
@@ -916,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;
@@ -950,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);
 
@@ -1143,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;
@@ -1571,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 32afd8a40b0faf22d1ef2de5bb2a2990fa6eebb3..2294c4564fba3e171334314a5623928c5f27c14a 100644 (file)
@@ -1,5 +1,8 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
+#include "../alloc.h"
+#include "../hash.h"
 #include "../refs.h"
+#include "../repository.h"
 #include "refs-internal.h"
 #include "ref-cache.h"
 #include "../iterator.h"
index 850d9d3744e94270fb5cd445b4f6b7b18aac8128..95c76e27c833112743b82a0b62f9a5423fb52259 100644 (file)
@@ -1,10 +1,11 @@
 #ifndef REFS_REF_CACHE_H
 #define REFS_REF_CACHE_H
 
-#include "cache.h"
+#include "hash-ll.h"
 
 struct ref_dir;
 struct ref_store;
+struct repository;
 
 /*
  * If this ref_cache is filled lazily, this function is used to load
index 69f93b0e2ac9fa9ec2778b783fa98792030c327e..9db8aec4da8eef6fb9542a9db5d1cbae01c129e6 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef REFS_REFS_INTERNAL_H
 #define REFS_REFS_INTERNAL_H
 
-#include "cache.h"
 #include "refs.h"
 #include "iterator.h"
 
@@ -368,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
@@ -548,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,
@@ -571,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 63e3112104a949e28e0cae1c8beaee0c27c099f1..d60932f4ded876476b7dec21456b9088260d0d1f 100644 (file)
--- a/refspec.c
+++ b/refspec.c
@@ -1,7 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "strvec.h"
 #include "refs.h"
 #include "refspec.h"
+#include "strbuf.h"
 
 static struct refspec_item s_tag_refspec = {
        .force = 0,
index 155953d1b82d4751dc80b1d486661e54d2ba16ba..ce936b4e1887ca982c9d814a014b469cbb49e52e 100644 (file)
@@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd
 */
 
 #include "git-compat-util.h"
-#include "hash.h"
+#include "hash-ll.h"
 
 #include "reftable-blocksource.h"
 #include "reftable-error.h"
index 93941f214570ace6e82e3c0a8b3c83d8b945405f..0d1766735e8ff0f1c5c057d1882728aa4292d1ee 100644 (file)
@@ -6,6 +6,7 @@ license that can be found in the LICENSE file or at
 https://developers.google.com/open-source/licenses/bsd
 */
 
+#include "system.h"
 #include "reftable-error.h"
 
 #include <stdio.h>
index 0ad7d5c0ff225cf0904e5dc2ddfe09c0486710d8..bcb82530d6ce35e8a0a582d9718090067b238899 100644 (file)
@@ -6,10 +6,10 @@ license that can be found in the LICENSE file or at
 https://developers.google.com/open-source/licenses/bsd
 */
 
+#include "system.h"
 #include "reftable-malloc.h"
 
 #include "basics.h"
-#include "system.h"
 
 static void *(*reftable_malloc_ptr)(size_t sz);
 static void *(*reftable_realloc_ptr)(void *, size_t);
index 18f9207dfee16accdaac46a77d13b9960aad3ca2..6b74a8151436144225c2e579340dfc3426a26470 100644 (file)
@@ -13,7 +13,7 @@ https://developers.google.com/open-source/licenses/bsd
 
 #include "git-compat-util.h"
 #include "strbuf.h"
-#include "hash.h" /* hash ID, sizes.*/
+#include "hash-ll.h" /* hash ID, sizes.*/
 #include "dir.h" /* remove_dir_recursively, for tests.*/
 
 int hash_size(uint32_t id);
index b8899e060abdd6629d73510a8b126b0c00c90b8d..a5bf880985472dee7cd7c9169047752245599488 100644 (file)
@@ -6,10 +6,10 @@ license that can be found in the LICENSE file or at
 https://developers.google.com/open-source/licenses/bsd
 */
 
+#include "system.h"
 #include "tree.h"
 
 #include "basics.h"
-#include "system.h"
 
 struct tree_node *tree_search(void *key, struct tree_node **rootp,
                              int (*compare)(const void *, const void *),
index cbff12558868a2ad29337da146ed7c34d063634c..ac3a045ad4afbc893f4daff8da98c768cabaf8fd 100644 (file)
@@ -6,6 +6,7 @@ license that can be found in the LICENSE file or at
 https://developers.google.com/open-source/licenses/bsd
 */
 
+#include "system.h"
 #include "tree.h"
 
 #include "basics.h"
index a76b6405eb2fc443ff22b93b1598892d02508e20..ef05752ca5738ea16d16d38c8ea9c65e2a9ea167 100644 (file)
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "remote.h"
 #include "connect.h"
 #include "strbuf.h"
 #include "credential.h"
 #include "oid-array.h"
 #include "send-pack.h"
+#include "setup.h"
 #include "protocol.h"
 #include "quote.h"
+#include "trace2.h"
 #include "transport.h"
+#include "write-or-die.h"
 
 static struct remote *remote;
 /* always ends with a trailing slash */
@@ -472,10 +478,11 @@ static struct discovery *discover_refs(const char *service, int for_push)
 
        /*
         * NEEDSWORK: If we are trying to use protocol v2 and we are planning
-        * to perform a push, then fallback to v0 since the client doesn't know
-        * how to push yet using v2.
+        * to perform any operation that doesn't involve upload-pack (i.e., a
+        * fetch, ls-remote, etc), then fallback to v0 since we don't know how
+        * to do anything else (like push or remote archive) via v2.
         */
-       if (version == protocol_v2 && !strcmp("git-receive-pack", service))
+       if (version == protocol_v2 && strcmp("git-upload-pack", service))
                version = protocol_v0;
 
        /* Add the extra Git-Protocol header */
@@ -755,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 60869beebe7364a594cd45938d4ed97dcdd28840..abb24822beb2a17187d4afa9474dd1c537f078ba 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1,20 +1,28 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "remote.h"
 #include "urlmatch.h"
 #include "refs.h"
 #include "refspec.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
 #include "dir.h"
 #include "tag.h"
+#include "setup.h"
 #include "string-list.h"
 #include "strvec.h"
 #include "commit-reach.h"
 #include "advice.h"
 #include "connect.h"
+#include "parse-options.h"
 
 enum map_direction { FROM_SRC, FROM_DST };
 
@@ -341,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;
@@ -349,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. */
@@ -406,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);
@@ -882,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;
 
        /*
@@ -1163,7 +1173,7 @@ static int try_explicit_object_name(const char *name,
                return 0;
        }
 
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                return -1;
 
        if (match) {
@@ -1251,7 +1261,7 @@ static void show_push_unqualified_ref_name_error(const char *dst_value,
        if (!advice_enabled(ADVICE_PUSH_UNQUALIFIED_REF_NAME))
                return;
 
-       if (get_oid(matched_src_name, &oid))
+       if (repo_get_oid(the_repository, matched_src_name, &oid))
                BUG("'%s' is not a valid object, "
                    "match_explicit_lhs() should catch this!",
                    matched_src_name);
@@ -1759,7 +1769,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
                        if (starts_with(ref->name, "refs/tags/"))
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
-                       else if (!has_object_file(&ref->old_oid))
+                       else if (!repo_has_object_file(the_repository, &ref->old_oid))
                                reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
                        else if (!lookup_commit_reference_gently(the_repository, &ref->old_oid, 1) ||
                                 !lookup_commit_reference_gently(the_repository, &ref->new_oid, 1))
@@ -1808,8 +1818,9 @@ static void set_merge(struct remote_state *remote_state, struct branch *ret)
                if (!remote_find_tracking(remote, ret->merge[i]) ||
                    strcmp(ret->remote_name, "."))
                        continue;
-               if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]),
-                            &oid, &ref, 0) == 1)
+               if (repo_dwim_ref(the_repository, ret->merge_name[i],
+                                 strlen(ret->merge_name[i]), &oid, &ref,
+                                 0) == 1)
                        ret->merge[i]->dst = ref;
                else
                        ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
@@ -2248,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;
@@ -2311,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;
@@ -2505,7 +2518,7 @@ static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, i
                entry->use_tracking = 1;
        else if (!colon[1])
                oidclr(&entry->expect);
-       else if (get_oid(colon + 1, &entry->expect))
+       else if (repo_get_oid(the_repository, colon + 1, &entry->expect))
                return error(_("cannot parse expected object name '%s'"),
                             colon + 1);
        return 0;
@@ -2662,7 +2675,7 @@ static int is_reachable_in_reflog(const char *local, const struct ref *remote)
                if (MERGE_BASES_BATCH_SIZE < size)
                        size = MERGE_BASES_BATCH_SIZE;
 
-               if ((ret = in_merge_bases_many(commit, size, chunk)))
+               if ((ret = repo_in_merge_bases_many(the_repository, commit, size, chunk)))
                        break;
        }
 
index 1ebbe42792ec67230b62dbbe4cb8ed9646576858..cdc8b1db42c4a836804009a036628aaa94d94b5a 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -1,11 +1,11 @@
 #ifndef REMOTE_H
 #define REMOTE_H
 
-#include "cache.h"
-#include "parse-options.h"
+#include "hash-ll.h"
 #include "hashmap.h"
 #include "refspec.h"
 
+struct option;
 struct transport_ls_refs_options;
 
 /**
@@ -380,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 320be2522d80a87fdb1569a97c5e24b77fd4a525..523215589de9221b0823aab9edbb06389ca52825 100644 (file)
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#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"
@@ -62,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)
@@ -82,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 3fbc32eb7b7ef7bf9119f83aa7e3a4b6c20104b3..66c41b938b44f4ba0a94521c4344aca0ca19087e 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "oidmap.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 struct replace_object {
        struct oidmap_entry original;
@@ -19,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
@@ -33,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 3dbd3f0e2ec33df0753780f4d84605b16ebdc2b3..525f69c0c7785845cdf8991e56c8d231c2e6d239 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "repository.h"
 #include "midx.h"
@@ -43,7 +43,7 @@ void prepare_repo_settings(struct repository *r)
        /* Defaults modified by feature.* */
        if (experimental) {
                r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
-               r->settings.gc_cruft_packs = 1;
+               r->settings.pack_use_bitmap_boundary_traversal = 1;
        }
        if (manyfiles) {
                r->settings.index_version = 4;
@@ -63,6 +63,11 @@ void prepare_repo_settings(struct repository *r)
        repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
        repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
        repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
+       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 937fa974b38e86a1873a0e6904cd4c35ac5fd8f1..a7679ceeaa45ce7a20094f9a29a82987290ad354 100644 (file)
@@ -3,15 +3,20 @@
  * 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"
 #include "sparse-index.h"
+#include "trace2.h"
 #include "promisor-remote.h"
 
 /* The main repository */
@@ -179,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 e8c67ffe16542425b3660b88f2dcf339a473369e..5f18486f6465c44b44abb2ded74bcdda14ba7bd9 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef REPOSITORY_H
 #define REPOSITORY_H
 
-#include "git-compat-util.h"
-#include "path.h"
-
 struct config_set;
 struct fsmonitor_settings;
 struct git_hash_algo;
@@ -34,10 +31,20 @@ struct repo_settings {
        int commit_graph_generation_version;
        int commit_graph_read_changed_paths;
        int gc_write_commit_graph;
-       int gc_cruft_packs;
        int fetch_write_commit_graph;
        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 */
 
@@ -164,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
@@ -221,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 876ab435da949c8359c315636225d9fd7fd962ab..725c1b6a95cdedd89152a0f80b8fe2477751458e 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -1,15 +1,22 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.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-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "hash-lookup.h"
 #include "strmap.h"
 
@@ -197,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] != '.') {
@@ -965,8 +972,9 @@ static int handle_cache(struct index_state *istate,
                        break;
                i = ce_stage(ce) - 1;
                if (!mmfile[i].ptr) {
-                       mmfile[i].ptr = read_object_file(&ce->oid, &type,
-                                                        &size);
+                       mmfile[i].ptr = repo_read_object_file(the_repository,
+                                                             &ce->oid, &type,
+                                                             &size);
                        mmfile[i].size = size;
                }
        }
index c32d79c3bd81f1ff6e9247b77a050784b917ecfd..5d6cb638793a4982e6b1e2cd1960dbb6ce0e6dd6 100644 (file)
--- a/rerere.h
+++ b/rerere.h
@@ -1,6 +1,7 @@
 #ifndef RERERE_H
 #define RERERE_H
 
+#include "gettext.h"
 #include "string-list.h"
 
 struct pathspec;
@@ -24,9 +25,6 @@ struct rerere_id {
 };
 
 int setup_rerere(struct repository *,struct string_list *, int);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define rerere(flags) repo_rerere(the_repository, flags)
-#endif
 int repo_rerere(struct repository *, int);
 /*
  * Given the conflict ID and the name of a "file" used for replaying
diff --git a/reset.c b/reset.c
index 5ded23611f3f7316e2327872a54474ce6e4f6200..48da0adf851e1b09edfc22ffbbc0b1128cbbc5ab 100644 (file)
--- a/reset.c
+++ b/reset.c
@@ -1,6 +1,9 @@
 #include "git-compat-util.h"
 #include "cache-tree.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
+#include "object-name.h"
 #include "refs.h"
 #include "reset.h"
 #include "run-command.h"
@@ -38,7 +41,7 @@ static int update_refs(const struct reset_head_opts *opts,
        prefix_len = msg.len;
 
        if (update_orig_head) {
-               if (!get_oid("ORIG_HEAD", &oid_old_orig))
+               if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
                        old_orig = &oid_old_orig;
                if (head) {
                        if (!reflog_orig_head) {
@@ -106,7 +109,7 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
                goto leave_reset_head;
        }
 
-       if (!get_oid("HEAD", &head_oid)) {
+       if (!repo_get_oid(r, "HEAD", &head_oid)) {
                head = &head_oid;
        } else if (!oid || !reset_hard) {
                ret = error(_("could not determine HEAD revision"));
diff --git a/reset.h b/reset.h
index a28f81829d859dc3dfd3817d6449ab7eb195b0d3..10708d8ddc0040f86b5b1f400bfb14d932dffe8e 100644 (file)
--- a/reset.h
+++ b/reset.h
@@ -1,7 +1,7 @@
 #ifndef RESET_H
 #define RESET_H
 
-#include "hash.h"
+#include "hash-ll.h"
 #include "repository.h"
 
 #define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
index e81096e2d459bd9391a5a8572fef2aae23d717ab..7817f5d6db178519c23b4eea66785820cb4315ca 100644 (file)
@@ -1,6 +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 */
index 2b3f0f901e63aeab70dfca86d3067d169dc315e2..c5deafc92fe7751532162ec308cf2bd62d97cf1b 100644 (file)
@@ -1,7 +1,12 @@
 #ifndef RESOLVE_UNDO_H
 #define RESOLVE_UNDO_H
 
-#include "cache.h"
+struct cache_entry;
+struct index_state;
+struct pathspec;
+struct string_list;
+
+#include "hash-ll.h"
 
 struct resolve_undo_info {
        unsigned int mode[3];
index 21f5f572c22ec7054da6bc20fef26ee2a59a19d5..2f4c53ea207b22a68097708b327884ae970c1978 100644 (file)
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "tag.h"
 #include "blob.h"
 #include "tree.h"
 #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"
 #include "commit-graph.h"
 #include "prio-queue.h"
@@ -35,6 +44,8 @@
 #include "json-writer.h"
 #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;
 
@@ -324,7 +335,8 @@ static void add_pending_object_with_path(struct rev_info *revs,
        if (revs->reflog_info && obj->type == OBJ_COMMIT) {
                struct strbuf buf = STRBUF_INIT;
                size_t namelen = strlen(name);
-               int len = interpret_branch_name(name, namelen, &buf, &options);
+               int len = repo_interpret_branch_name(the_repository, name,
+                                                    namelen, &buf, &options);
 
                if (0 < len && len < namelen && buf.len)
                        strbuf_addstr(&buf, name + len);
@@ -354,7 +366,7 @@ void add_head_to_pending(struct rev_info *revs)
 {
        struct object_id oid;
        struct object *obj;
-       if (get_oid("HEAD", &oid))
+       if (repo_get_oid(the_repository, "HEAD", &oid))
                return;
        obj = parse_object(revs->repo, &oid);
        if (!obj)
@@ -777,8 +789,8 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
 static int rev_compare_tree(struct rev_info *revs,
                            struct commit *parent, struct commit *commit, int nth_parent)
 {
-       struct tree *t1 = get_commit_tree(parent);
-       struct tree *t2 = get_commit_tree(commit);
+       struct tree *t1 = repo_get_commit_tree(the_repository, parent);
+       struct tree *t2 = repo_get_commit_tree(the_repository, commit);
        int bloom_ret = 1;
 
        if (!t1)
@@ -824,7 +836,7 @@ static int rev_compare_tree(struct rev_info *revs,
 
 static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 {
-       struct tree *t1 = get_commit_tree(commit);
+       struct tree *t1 = repo_get_commit_tree(the_repository, commit);
 
        if (!t1)
                return 0;
@@ -962,7 +974,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        if (!revs->prune)
                return;
 
-       if (!get_commit_tree(commit))
+       if (!repo_get_commit_tree(the_repository, commit))
                return;
 
        if (!commit->parents) {
@@ -1548,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;
 }
 
@@ -1562,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;
@@ -1574,7 +1588,8 @@ void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section)
 {
        struct exclude_hidden_refs_cb cb;
 
-       if (strcmp(section, "receive") && strcmp(section, "uploadpack"))
+       if (strcmp(section, "fetch") && strcmp(section, "receive") &&
+                       strcmp(section, "uploadpack"))
                die(_("unsupported section for hidden refs: %s"), section);
 
        if (exclusions->hidden_refs_configured)
@@ -1867,7 +1882,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
                flags ^= UNINTERESTING | BOTTOM;
                arg++;
        }
-       if (get_oid_committish(arg, &oid))
+       if (repo_get_oid_committish(the_repository, arg, &oid))
                return 0;
        while (1) {
                it = get_reference(revs, arg, &oid, 0);
@@ -1948,15 +1963,15 @@ static void prepare_show_merge(struct rev_info *revs)
        int i, prune_num = 1; /* counting terminating NULL */
        struct index_state *istate = revs->repo->index;
 
-       if (get_oid("HEAD", &oid))
+       if (repo_get_oid(the_repository, "HEAD", &oid))
                die("--merge without HEAD?");
        head = lookup_commit_or_die(&oid, "HEAD");
-       if (get_oid("MERGE_HEAD", &oid))
+       if (repo_get_oid(the_repository, "MERGE_HEAD", &oid))
                die("--merge without MERGE_HEAD?");
        other = lookup_commit_or_die(&oid, "MERGE_HEAD");
        add_pending_object(revs, &head->object, "HEAD");
        add_pending_object(revs, &other->object, "MERGE_HEAD");
-       bases = get_merge_bases(head, other);
+       bases = repo_get_merge_bases(the_repository, head, other);
        add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
        add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
        free_commit_list(bases);
@@ -2051,7 +2066,7 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
                if (!a || !b)
                        return dotdot_missing(arg, dotdot, revs, symmetric);
 
-               exclude = get_merge_bases(a, b);
+               exclude = repo_get_merge_bases(the_repository, a, b);
                add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
                                     flags_exclude);
                add_pending_commit_list(revs, exclude, flags_exclude);
@@ -2184,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);
@@ -2659,7 +2641,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;
 }
@@ -2805,6 +2787,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,
+                                     int *flags)
+{
+       struct strbuf sb;
+       int seen_dashdash = 0;
+       int seen_end_of_options = 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) {
+               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, 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 NORETURN diagnose_missing_default(const char *def)
 {
        int flags;
@@ -2877,7 +2906,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                                }
                                if (revs->read_from_stdin++)
                                        die("--stdin given twice?");
-                               read_revisions_from_stdin(revs, &prune_data);
+                               read_revisions_from_stdin(revs, &prune_data, &flags);
                                continue;
                        }
 
@@ -2941,7 +2970,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) {
@@ -3440,8 +3469,8 @@ void reset_revision_walk(void)
 }
 
 static int mark_uninteresting(const struct object_id *oid,
-                             struct packed_git *pack,
-                             uint32_t pos,
+                             struct packed_git *pack UNUSED,
+                             uint32_t pos UNUSED,
                              void *cb)
 {
        struct rev_info *revs = cb;
@@ -3877,7 +3906,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
         * in it.
         */
        encoding = get_log_output_encoding();
-       message = logmsg_reencode(commit, NULL, encoding);
+       message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
 
        /* Copy the commit to temporary if we are using "fake" headers */
        if (buf.len)
@@ -3913,7 +3942,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                retval = grep_buffer(&opt->grep_filter,
                                     (char *)message, strlen(message));
        strbuf_release(&buf);
-       unuse_commit_buffer(commit, message);
+       repo_unuse_commit_buffer(the_repository, commit, message);
        return retval;
 }
 
@@ -4159,7 +4188,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
  * Return true for entries that have not yet been shown.  (This is an
  * object_array_each_func_t.)
  */
-static int entry_unshown(struct object_array_entry *entry, void *cb_data_unused)
+static int entry_unshown(struct object_array_entry *entry, void *cb_data UNUSED)
 {
        return !(entry->item->flags & SHOWN);
 }
index 30febad09a1e3493ed9b89cd57486134cc120f14..82ab400139de30fd6af5e00f2047c51a62a8ed7d 100644 (file)
@@ -2,13 +2,15 @@
 #define REVISION_H
 
 #include "commit.h"
-#include "parse-options.h"
 #include "grep.h"
 #include "notes.h"
 #include "pretty.h"
 #include "diff.h"
 #include "commit-slab-decl.h"
+#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
@@ -61,6 +63,8 @@ struct string_list;
 struct saved_parents;
 struct bloom_key;
 struct bloom_filter_settings;
+struct option;
+struct parse_opt_ctx_t;
 define_shared_commit_slab(revision_sources, char *);
 
 struct rev_cmdline_info {
@@ -84,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;
 
@@ -92,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
@@ -107,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;
@@ -415,9 +419,6 @@ struct rev_info {
 void repo_init_revisions(struct repository *r,
                         struct rev_info *revs,
                         const char *prefix);
-#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
-#define init_revisions(revs, prefix) repo_init_revisions(the_repository, revs, prefix)
-#endif
 
 /**
  * Parse revision information, filling in the `rev_info` structure, and
@@ -428,7 +429,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 6bd16acb0603b16a71c729978bba812326ca9400..a558042c876ad2baefcfcc111163bab9691f7f1c 100644 (file)
@@ -1,16 +1,22 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "run-command.h"
+#include "environment.h"
 #include "exec-cmd.h"
+#include "gettext.h"
 #include "sigchain.h"
 #include "strvec.h"
+#include "symlinks.h"
 #include "thread-utils.h"
 #include "strbuf.h"
 #include "string-list.h"
+#include "trace.h"
+#include "trace2.h"
 #include "quote.h"
 #include "config.h"
 #include "packfile.h"
 #include "hook.h"
 #include "compat/nonblock.h"
+#include "alloc.h"
 
 void child_process_init(struct child_process *child)
 {
@@ -164,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
@@ -212,6 +219,7 @@ static char *locate_in_PATH(const char *file)
        strbuf_release(&buf);
        return NULL;
 }
+#endif
 
 int exists_in_PATH(const char *command)
 {
@@ -301,7 +309,6 @@ enum child_errcode {
        CHILD_ERR_DUP2,
        CHILD_ERR_CLOSE,
        CHILD_ERR_SIGPROCMASK,
-       CHILD_ERR_ENOENT,
        CHILD_ERR_SILENT,
        CHILD_ERR_ERRNO
 };
@@ -341,19 +348,19 @@ static void child_close_pair(int fd[2])
        child_close(fd[1]);
 }
 
-static void child_error_fn(const char *err, va_list params)
+static void child_error_fn(const char *err UNUSED, va_list params UNUSED)
 {
        const char msg[] = "error() should not be called in child\n";
        xwrite(2, msg, sizeof(msg) - 1);
 }
 
-static void child_warn_fn(const char *err, va_list params)
+static void child_warn_fn(const char *err UNUSED, va_list params UNUSED)
 {
        const char msg[] = "warn() should not be called in child\n";
        xwrite(2, msg, sizeof(msg) - 1);
 }
 
-static void NORETURN child_die_fn(const char *err, va_list params)
+static void NORETURN child_die_fn(const char *err UNUSED, va_list params UNUSED)
 {
        const char msg[] = "die() should not be called in child\n";
        xwrite(2, msg, sizeof(msg) - 1);
@@ -384,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:
@@ -840,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 ca19b95ce46cfdaa6f501eb487d4ba869fd0c5bd..fb2940c2a00c94d806319dc8d45e8ffed1231c17 100644 (file)
--- a/scalar.c
+++ b/scalar.c
@@ -2,7 +2,8 @@
  * The Scalar command-line interface.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "config.h"
@@ -14,6 +15,8 @@
 #include "dir.h"
 #include "packfile.h"
 #include "help.h"
+#include "setup.h"
+#include "trace2.h"
 
 static void setup_enlistment_directory(int argc, const char **argv,
                                       const char * const *usagestr,
@@ -406,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")),
@@ -414,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;
@@ -453,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)
@@ -563,7 +573,7 @@ static int cmd_diagnose(int argc, const char **argv)
        return res;
 }
 
-static int cmd_list(int argc, const char **argv)
+static int cmd_list(int argc, const char **argv UNUSED)
 {
        if (argc != 1)
                die(_("`scalar list` does not take arguments"));
@@ -591,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;
 
@@ -652,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);
@@ -662,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 f2e19838c9c342b3b9d6df5e9bf24d0add0d47d1..89aca9d829ed046f532b87120f39d807c86ebcb9 100644 (file)
@@ -1,8 +1,11 @@
-#include "builtin.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "commit.h"
+#include "date.h"
+#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"
 #include "version.h"
 #include "oid-array.h"
 #include "gpg-interface.h"
-#include "cache.h"
 #include "shallow.h"
+#include "parse-options.h"
+#include "trace2.h"
+#include "write-or-die.h"
 
 int option_parse_push_signed(const struct option *opt,
                             const char *arg, int unset)
@@ -42,9 +47,9 @@ int option_parse_push_signed(const struct option *opt,
 static void feed_object(const struct object_id *oid, FILE *fh, int negative)
 {
        if (negative &&
-           !has_object_file_with_flags(oid,
-                                       OBJECT_INFO_SKIP_FETCH_OBJECT |
-                                       OBJECT_INFO_QUICK))
+           !repo_has_object_file_with_flags(the_repository, oid,
+                                            OBJECT_INFO_SKIP_FETCH_OBJECT |
+                                            OBJECT_INFO_QUICK))
                return;
 
        if (negative)
@@ -534,7 +539,7 @@ int send_pack(struct send_pack_args *args,
                die(_("the receiving end does not support this repository's hash algorithm"));
 
        if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
-               int len;
+               size_t len;
                push_cert_nonce = server_feature_value("push-cert", &len);
                if (push_cert_nonce) {
                        reject_invalid_nonce(push_cert_nonce, len);
index 1c96a75b1e9f8bbe9a7a2e40a3d4dd7bb80a9335..81e1ad5832b242054a9796cff9ac16c5fd4b6499 100644 (file)
@@ -1,9 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "advice.h"
 #include "config.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "lockfile.h"
 #include "dir.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "object.h"
+#include "pager.h"
 #include "commit.h"
 #include "sequencer.h"
 #include "tag.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"
 
 #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 ";
 
@@ -126,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
@@ -208,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;
@@ -263,11 +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);
 
-       status = git_gpg_config(k, v, NULL);
-       if (status)
-               return status;
-
-       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)
@@ -357,9 +380,7 @@ void replay_opts_release(struct replay_opts *opts)
        free(opts->reflog_action);
        free(opts->default_strategy);
        free(opts->strategy);
-       for (size_t i = 0; i < opts->xopts_nr; i++)
-               free(opts->xopts[i]);
-       free(opts->xopts);
+       strvec_clear (&opts->xopts);
        strbuf_release(&opts->current_fixups);
        if (opts->revs)
                release_revisions(opts->revs);
@@ -419,7 +440,8 @@ struct commit_message {
 
 static const char *short_commit_name(struct commit *commit)
 {
-       return find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV);
+       return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+                                      DEFAULT_ABBREV);
 }
 
 static int get_message(struct commit *commit, struct commit_message *out)
@@ -427,7 +449,8 @@ static int get_message(struct commit *commit, struct commit_message *out)
        const char *abbrev, *subject;
        int subject_len;
 
-       out->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+       out->message = repo_logmsg_reencode(the_repository, commit, NULL,
+                                           get_commit_output_encoding());
        abbrev = short_commit_name(commit);
 
        subject_len = find_commit_subject(out->message, &subject);
@@ -444,7 +467,7 @@ static void free_message(struct commit *commit, struct commit_message *msg)
        free(msg->parent_label);
        free(msg->label);
        free(msg->subject);
-       unuse_commit_buffer(commit, msg->message);
+       repo_unuse_commit_buffer(the_repository, commit, msg->message);
 }
 
 static void print_advice(struct repository *r, int show_hint,
@@ -561,7 +584,7 @@ static void update_abort_safety_file(void)
        if (!file_exists(git_path_seq_dir()))
                return;
 
-       if (!get_oid("HEAD", &head))
+       if (!repo_get_oid(the_repository, "HEAD", &head))
                write_file(git_path_abort_safety_file(), "%s", oid_to_hex(&head));
        else
                write_file(git_path_abort_safety_file(), "%s", "");
@@ -653,11 +676,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++;
@@ -692,11 +716,11 @@ static int do_recursive_merge(struct repository *r,
        o.show_rename_progress = 1;
 
        head_tree = parse_tree_indirect(head);
-       next_tree = next ? get_commit_tree(next) : empty_tree(r);
-       base_tree = base ? get_commit_tree(base) : empty_tree(r);
+       next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
+       base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
 
-       for (i = 0; i < opts->xopts_nr; i++)
-               parse_merge_opt(&o, opts->xopts[i]);
+       for (i = 0; i < opts->xopts.nr; i++)
+               parse_merge_opt(&o, opts->xopts.v[i]);
 
        if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
                memset(&result, 0, sizeof(result));
@@ -766,12 +790,12 @@ static int is_index_unchanged(struct repository *r)
        /*
         * If head_commit is NULL, check_commit, called from
         * lookup_commit, would have indicated that head_commit is not
-        * a commit object already.  parse_commit() will return failure
+        * a commit object already.  repo_parse_commit() will return failure
         * without further complaints in such a case.  Otherwise, if
-        * the commit is invalid, parse_commit() will complain.  So
+        * the commit is invalid, repo_parse_commit() will complain.  So
         * there is nothing for us to say here.  Just return failure.
         */
-       if (parse_commit(head_commit))
+       if (repo_parse_commit(r, head_commit))
                return -1;
 
        if (!(cache_tree_oid = get_cache_tree_oid(istate)))
@@ -1136,7 +1160,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');
 }
 
 /*
@@ -1167,7 +1192,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);
@@ -1336,13 +1362,15 @@ void print_commit_summary(struct repository *r,
        commit = lookup_commit(r, oid);
        if (!commit)
                die(_("couldn't look up newly created commit"));
-       if (parse_commit(commit))
+       if (repo_parse_commit(r, commit))
                die(_("could not parse newly created commit"));
 
        strbuf_addstr(&format, "format:%h] %s");
 
-       format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
-       format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
+       repo_format_commit_message(r, commit, "%an <%ae>", &author_ident,
+                                  &pctx);
+       repo_format_commit_message(r, commit, "%cn <%ce>", &committer_ident,
+                                  &pctx);
        if (strbuf_cmp(&author_ident, &committer_ident)) {
                strbuf_addstr(&format, "\n Author: ");
                strbuf_addbuf_percentquote(&format, &author_ident);
@@ -1350,7 +1378,7 @@ void print_commit_summary(struct repository *r,
        if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
                struct strbuf date = STRBUF_INIT;
 
-               format_commit_message(commit, "%ad", &date, &pctx);
+               repo_format_commit_message(r, commit, "%ad", &date, &pctx);
                strbuf_addstr(&format, "\n Date: ");
                strbuf_addbuf_percentquote(&format, &date);
                strbuf_release(&date);
@@ -1380,7 +1408,7 @@ void print_commit_summary(struct repository *r,
        rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
        diff_setup_done(&rev.diffopt);
 
-       refs = get_main_ref_store(the_repository);
+       refs = get_main_ref_store(r);
        head = refs_resolve_ref_unsafe(refs, "HEAD", 0, NULL, NULL);
        if (!head)
                die(_("unable to resolve HEAD after creating commit"));
@@ -1406,7 +1434,7 @@ static int parse_head(struct repository *r, struct commit **head)
        struct commit *current_head;
        struct object_id oid;
 
-       if (get_oid("HEAD", &oid)) {
+       if (repo_get_oid(r, "HEAD", &oid)) {
                current_head = NULL;
        } else {
                current_head = lookup_commit_reference(r, &oid);
@@ -1416,7 +1444,7 @@ static int parse_head(struct repository *r, struct commit **head)
                        warning(_("HEAD %s is not a commit!"),
                                oid_to_hex(&oid));
                }
-               if (parse_commit(current_head))
+               if (repo_parse_commit(r, current_head))
                        return error(_("could not parse HEAD commit"));
        }
        *head = current_head;
@@ -1459,8 +1487,8 @@ static int try_to_commit(struct repository *r,
        if (flags & AMEND_MSG) {
                const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
                const char *out_enc = get_commit_output_encoding();
-               const char *message = logmsg_reencode(current_head, NULL,
-                                                     out_enc);
+               const char *message = repo_logmsg_reencode(r, current_head,
+                                                          NULL, out_enc);
 
                if (!msg) {
                        const char *orig_message = NULL;
@@ -1471,7 +1499,8 @@ static int try_to_commit(struct repository *r,
                        hook_commit = "HEAD";
                }
                author = amend_author = get_author(message);
-               unuse_commit_buffer(current_head, message);
+               repo_unuse_commit_buffer(r, current_head,
+                                        message);
                if (!author) {
                        res = error(_("unable to parse commit author"));
                        goto out;
@@ -1536,7 +1565,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;
@@ -1668,12 +1698,12 @@ static int is_original_commit_empty(struct commit *commit)
 {
        const struct object_id *ptree_oid;
 
-       if (parse_commit(commit))
+       if (repo_parse_commit(the_repository, commit))
                return error(_("could not parse commit %s"),
                             oid_to_hex(&commit->object.oid));
        if (commit->parents) {
                struct commit *parent = commit->parents->item;
-               if (parse_commit(parent))
+               if (repo_parse_commit(the_repository, parent))
                        return error(_("could not parse parent commit %s"),
                                oid_to_hex(&parent->object.oid));
                ptree_oid = get_commit_tree_oid(parent);
@@ -1830,7 +1860,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? */
@@ -1929,7 +1959,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);
@@ -1997,17 +2027,18 @@ static int update_squash_messages(struct repository *r,
                struct commit *head_commit;
                const char *head_message, *body;
 
-               if (get_oid("HEAD", &head))
+               if (repo_get_oid(r, "HEAD", &head))
                        return error(_("need a HEAD to fixup"));
                if (!(head_commit = lookup_commit_reference(r, &head)))
                        return error(_("could not read HEAD"));
-               if (!(head_message = logmsg_reencode(head_commit, NULL, encoding)))
+               if (!(head_message = repo_logmsg_reencode(r, head_commit, NULL,
+                                                         encoding)))
                        return error(_("could not read HEAD's commit message"));
 
                find_commit_subject(head_message, &body);
                if (command == TODO_FIXUP && !flag && write_message(body, strlen(body),
                                                        rebase_path_fixup_msg(), 0) < 0) {
-                       unuse_commit_buffer(head_commit, head_message);
+                       repo_unuse_commit_buffer(r, head_commit, head_message);
                        return error(_("cannot write '%s'"), rebase_path_fixup_msg());
                }
                strbuf_addf(&buf, "%c ", comment_line_char);
@@ -2018,14 +2049,15 @@ 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);
 
-               unuse_commit_buffer(head_commit, head_message);
+               repo_unuse_commit_buffer(r, head_commit, head_message);
        }
 
-       if (!(message = logmsg_reencode(commit, NULL, encoding)))
+       if (!(message = repo_logmsg_reencode(r, commit, NULL, encoding)))
                return error(_("could not read commit message of %s"),
                             oid_to_hex(&commit->object.oid));
        find_commit_subject(message, &body);
@@ -2037,10 +2069,11 @@ 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);
-       unuse_commit_buffer(commit, message);
+       repo_unuse_commit_buffer(r, commit, message);
 
        if (!res)
                res = write_message(buf.buf, buf.len, rebase_path_squash_msg(),
@@ -2067,7 +2100,7 @@ static void flush_rewritten_pending(void)
        FILE *out;
 
        if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), (GIT_MAX_HEXSZ + 1) * 2) > 0 &&
-           !get_oid("HEAD", &newoid) &&
+           !repo_get_oid(the_repository, "HEAD", &newoid) &&
            (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
                char *bol = buf.buf, *eol;
 
@@ -2119,7 +2152,8 @@ static void refer_to_commit(struct replay_opts *opts,
                        .abbrev = DEFAULT_ABBREV,
                        .date_mode.type = DATE_SHORT,
                };
-               format_commit_message(commit, "%h (%s, %ad)", msgbuf, &ctx);
+               repo_format_commit_message(the_repository, commit,
+                                          "%h (%s, %ad)", msgbuf, &ctx);
        } else {
                strbuf_addstr(msgbuf, oid_to_hex(&commit->object.oid));
        }
@@ -2152,7 +2186,7 @@ static int do_pick_commit(struct repository *r,
                if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL))
                        return error(_("your index file is unmerged."));
        } else {
-               unborn = get_oid("HEAD", &head);
+               unborn = repo_get_oid(r, "HEAD", &head);
                /* Do we want to generate a root commit? */
                if (is_pick_or_similar(command) && opts->have_squash_onto &&
                    oideq(&head, &opts->squash_onto)) {
@@ -2214,7 +2248,7 @@ static int do_pick_commit(struct repository *r,
                msg_file = NULL;
                goto fast_forward_edit;
        }
-       if (parent && parse_commit(parent) < 0)
+       if (parent && repo_parse_commit(r, parent) < 0)
                /* TRANSLATORS: The first %s will be a "todo" command like
                   "revert" or "pick", the second %s a SHA1. */
                return error(_("%s: cannot parse parent commit %s"),
@@ -2327,7 +2361,7 @@ static int do_pick_commit(struct repository *r,
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
                res |= try_merge_command(r, opts->strategy,
-                                        opts->xopts_nr, (const char **)opts->xopts,
+                                        opts->xopts.nr, opts->xopts.v,
                                        common, oid_to_hex(&head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
@@ -2465,7 +2499,6 @@ void todo_list_release(struct todo_list *todo_list)
 static struct todo_item *append_new_todo(struct todo_list *todo_list)
 {
        ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);
-       todo_list->total_nr++;
        return todo_list->items + todo_list->nr++;
 }
 
@@ -2606,7 +2639,7 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
        end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
-       status = get_oid(bol, &commit_oid);
+       status = repo_get_oid(r, bol, &commit_oid);
        if (status < 0)
                error(_("could not parse '%s'"), bol); /* return later */
        *end_of_object_name = saved;
@@ -2656,7 +2689,7 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf,
        char *p = buf, *next_p;
        int i, res = 0, fixup_okay = file_exists(rebase_path_done());
 
-       todo_list->current = todo_list->nr = 0;
+       todo_list->current = todo_list->nr = todo_list->total_nr = 0;
 
        for (i = 1; *p; i++, p = next_p) {
                char *eol = strchrnul(p, '\n');
@@ -2677,10 +2710,13 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf,
                        item->commit = NULL;
                }
 
+               if (item->command != TODO_COMMENT)
+                       todo_list->total_nr++;
+
                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;
@@ -2867,7 +2903,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;
@@ -2875,36 +2913,35 @@ 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"))
                git_config_string_dup(&opts->gpg_sign, key, value);
        else if (!strcmp(key, "options.strategy-option")) {
-               ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
-               opts->xopts[opts->xopts_nr++] = xstrdup(value);
+               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;
@@ -2918,22 +2955,27 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
        return 0;
 }
 
-void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
+static void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
 {
        int i;
+       int count;
+       const char **argv;
        char *strategy_opts_string = raw_opts;
 
        if (*strategy_opts_string == ' ')
                strategy_opts_string++;
 
-       opts->xopts_nr = split_cmdline(strategy_opts_string,
-                                      (const char ***)&opts->xopts);
-       for (i = 0; i < opts->xopts_nr; i++) {
-               const char *arg = opts->xopts[i];
+       count = split_cmdline(strategy_opts_string, &argv);
+       if (count < 0)
+               BUG("could not split '%s': %s", strategy_opts_string,
+                           split_cmdline_strerror(count));
+       for (i = 0; i < count; i++) {
+               const char *arg = argv[i];
 
                skip_prefix(arg, "--", &arg);
-               opts->xopts[i] = xstrdup(arg);
+               strvec_push(&opts->xopts, arg);
        }
+       free(argv);
 }
 
 static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
@@ -2941,7 +2983,6 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
        strbuf_reset(buf);
        if (!read_oneliner(buf, rebase_path_strategy(), 0))
                return;
-       free(opts->strategy);
        opts->strategy = strbuf_detach(buf, NULL);
        if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
                return;
@@ -3022,7 +3063,7 @@ static int read_populate_opts(struct replay_opts *opts)
                }
 
                if (read_oneliner(&buf, rebase_path_squash_onto(), 0)) {
-                       if (get_oid_committish(buf.buf, &opts->squash_onto) < 0) {
+                       if (repo_get_oid_committish(the_repository, buf.buf, &opts->squash_onto) < 0) {
                                ret = error(_("unusable squash-onto"));
                                goto done_rebase_i;
                        }
@@ -3050,12 +3091,13 @@ done_rebase_i:
 
 static void write_strategy_opts(struct replay_opts *opts)
 {
-       int i;
        struct strbuf buf = STRBUF_INIT;
 
-       for (i = 0; i < opts->xopts_nr; ++i)
-               strbuf_addf(&buf, " --%s", opts->xopts[i]);
-
+       /*
+        * Quote strategy options so that they can be read correctly
+        * by split_cmdline().
+        */
+       quote_cmdline(&buf, opts->xopts.v);
        write_file(rebase_path_strategy_opts(), "%s\n", buf.buf);
        strbuf_release(&buf);
 }
@@ -3078,7 +3120,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
                write_file(rebase_path_verbose(), "%s", "");
        if (opts->strategy)
                write_file(rebase_path_strategy(), "%s\n", opts->strategy);
-       if (opts->xopts_nr > 0)
+       if (opts->xopts.nr > 0)
                write_strategy_opts(opts);
 
        if (opts->allow_rerere_auto == RERERE_AUTOUPDATE)
@@ -3122,7 +3164,9 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 
        while ((commit = get_revision(opts->revs))) {
                struct todo_item *item = append_new_todo(todo_list);
-               const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
+               const char *commit_buffer = repo_logmsg_reencode(the_repository,
+                                                                commit, NULL,
+                                                                encoding);
                const char *subject;
                int subject_len;
 
@@ -3134,7 +3178,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
                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);
-               unuse_commit_buffer(commit, commit_buffer);
+               repo_unuse_commit_buffer(the_repository, commit,
+                                        commit_buffer);
        }
 
        if (!todo_list->nr)
@@ -3184,25 +3229,7 @@ static int create_seq_dir(struct repository *r)
 
 static int save_head(const char *head)
 {
-       struct lock_file head_lock = LOCK_INIT;
-       struct strbuf buf = STRBUF_INIT;
-       int fd;
-       ssize_t written;
-
-       fd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);
-       if (fd < 0)
-               return error_errno(_("could not lock HEAD"));
-       strbuf_addf(&buf, "%s\n", head);
-       written = write_in_full(fd, buf.buf, buf.len);
-       strbuf_release(&buf);
-       if (written < 0) {
-               error_errno(_("could not write to '%s'"), git_path_head_file());
-               rollback_lock_file(&head_lock);
-               return -1;
-       }
-       if (commit_lock_file(&head_lock) < 0)
-               return error(_("failed to finalize '%s'"), git_path_head_file());
-       return 0;
+       return write_message(head, strlen(head), git_path_head_file(), 1);
 }
 
 static int rollback_is_safe(void)
@@ -3223,7 +3250,7 @@ static int rollback_is_safe(void)
        else
                die_errno(_("could not read '%s'"), git_path_abort_safety_file());
 
-       if (get_oid("HEAD", &actual_head))
+       if (repo_get_oid(the_repository, "HEAD", &actual_head))
                oidclr(&actual_head);
 
        return oideq(&actual_head, &expected_head);
@@ -3379,7 +3406,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);
@@ -3389,7 +3417,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);
@@ -3402,7 +3430,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;
@@ -3462,13 +3490,10 @@ static int save_opts(struct replay_opts *opts)
        if (opts->gpg_sign)
                res |= git_config_set_in_file_gently(opts_file,
                                        "options.gpg-sign", opts->gpg_sign);
-       if (opts->xopts) {
-               int i;
-               for (i = 0; i < opts->xopts_nr; i++)
-                       res |= git_config_set_multivar_in_file_gently(opts_file,
-                                       "options.strategy-option",
-                                       opts->xopts[i], "^$", 0);
-       }
+       for (size_t i = 0; i < opts->xopts.nr; i++)
+               res |= git_config_set_multivar_in_file_gently(opts_file,
+                               "options.strategy-option",
+                               opts->xopts.v[i], "^$", 0);
        if (opts->allow_rerere_auto)
                res |= git_config_set_in_file_gently(opts_file,
                                "options.allow-rerere-auto",
@@ -3486,18 +3511,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,25 +3531,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 = logmsg_reencode(commit, NULL, 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);
-               unuse_commit_buffer(commit, commit_buffer);
+               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;
@@ -3534,7 +3561,7 @@ static int intend_to_amend(void)
        struct object_id head;
        char *p;
 
-       if (get_oid("HEAD", &head))
+       if (repo_get_oid(the_repository, "HEAD", &head))
                return error(_("cannot read HEAD"));
 
        p = oid_to_hex(&head);
@@ -3625,14 +3652,14 @@ static int do_exec(struct repository *r, const char *command_line)
                          "  git rebase --continue\n"
                          "\n"),
                        command_line,
-                       dirty ? N_("and made changes to the index and/or the "
-                               "working tree\n") : "");
+                       dirty ? _("and made changes to the index and/or the "
+                               "working tree.\n") : "");
                if (status == 127)
                        /* command not found */
                        status = 1;
        } else if (dirty) {
                warning(_("execution succeeded: %s\nbut "
-                         "left changes to the index and/or the working tree\n"
+                         "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"
@@ -3673,7 +3700,6 @@ static int safe_append(const char *filename, const char *fmt, ...)
        }
        if (commit_lock_file(&lock) < 0) {
                strbuf_release(&buf);
-               rollback_lock_file(&lock);
                return error(_("failed to finalize '%s'"), filename);
        }
 
@@ -3700,7 +3726,7 @@ static int do_label(struct repository *r, const char *name, int len)
        if (!transaction) {
                error("%s", err.buf);
                ret = -1;
-       } else if (get_oid("HEAD", &head_oid)) {
+       } else if (repo_get_oid(r, "HEAD", &head_oid)) {
                error(_("could not read HEAD"));
                ret = -1;
        } else if (ref_transaction_update(transaction, ref_name.buf, &head_oid,
@@ -3878,7 +3904,7 @@ static int do_merge(struct repository *r,
        struct commit *head_commit, *merge_commit, *i;
        struct commit_list *bases, *j;
        struct commit_list *to_merge = NULL, **tail = &to_merge;
-       const char *strategy = !opts->xopts_nr &&
+       const char *strategy = !opts->xopts.nr &&
                (!opts->strategy ||
                 !strcmp(opts->strategy, "recursive") ||
                 !strcmp(opts->strategy, "ort")) ?
@@ -3988,7 +4014,8 @@ static int do_merge(struct repository *r,
 
        if (commit) {
                const char *encoding = get_commit_output_encoding();
-               const char *message = logmsg_reencode(commit, NULL, encoding);
+               const char *message = repo_logmsg_reencode(r, commit, NULL,
+                                                          encoding);
                const char *body;
                int len;
 
@@ -4001,7 +4028,7 @@ static int do_merge(struct repository *r,
                find_commit_subject(message, &body);
                len = strlen(body);
                ret = write_message(body, len, git_path_merge_msg(r), 0);
-               unuse_commit_buffer(commit, message);
+               repo_unuse_commit_buffer(r, commit, message);
                if (ret) {
                        error_errno(_("could not write '%s'"),
                                    git_path_merge_msg(r));
@@ -4061,9 +4088,9 @@ static int do_merge(struct repository *r,
                        strvec_push(&cmd.args, "octopus");
                else {
                        strvec_push(&cmd.args, strategy);
-                       for (k = 0; k < opts->xopts_nr; k++)
+                       for (k = 0; k < opts->xopts.nr; k++)
                                strvec_pushf(&cmd.args,
-                                            "-X%s", opts->xopts[k]);
+                                            "-X%s", opts->xopts.v[k]);
                }
                if (!(flags & TODO_EDIT_MERGE_MSG))
                        strvec_push(&cmd.args, "--no-edit");
@@ -4101,7 +4128,7 @@ static int do_merge(struct repository *r,
        }
 
        merge_commit = to_merge->item;
-       bases = get_merge_bases(head_commit, merge_commit);
+       bases = repo_get_merge_bases(r, head_commit, merge_commit);
        if (bases && oideq(&merge_commit->object.oid,
                           &bases->item->object.oid)) {
                ret = 0;
@@ -4141,6 +4168,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;
        }
        /*
@@ -4269,7 +4297,7 @@ void todo_list_filter_update_refs(struct repository *r,
                if (!is_null_oid(&rec->after))
                        continue;
 
-               for (j = 0; !found && j < todo_list->total_nr; j++) {
+               for (j = 0; !found && j < todo_list->nr; j++) {
                        struct todo_item *item = &todo_list->items[j];
                        const char *arg = todo_list->buf.buf + item->arg_offset;
 
@@ -4299,7 +4327,7 @@ void todo_list_filter_update_refs(struct repository *r,
         * For each todo_item, check if its ref is in the update_refs list.
         * If not, then add it as an un-updated ref.
         */
-       for (i = 0; i < todo_list->total_nr; i++) {
+       for (i = 0; i < todo_list->nr; i++) {
                struct todo_item *item = &todo_list->items[i];
                const char *arg = todo_list->buf.buf + item->arg_offset;
                int j, found = 0;
@@ -4456,7 +4484,7 @@ void create_autostash(struct repository *r, const char *path)
                if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
                        die(_("Cannot autostash"));
                strbuf_trim_trailing_newline(&buf);
-               if (get_oid(buf.buf, &oid))
+               if (repo_get_oid(r, buf.buf, &oid))
                        die(_("Unexpected stash response: '%s'"),
                            buf.buf);
                strbuf_reset(&buf);
@@ -4581,9 +4609,9 @@ static int stopped_at_head(struct repository *r)
        struct commit *commit;
        struct commit_message message;
 
-       if (get_oid("HEAD", &head) ||
+       if (repo_get_oid(r, "HEAD", &head) ||
            !(commit = lookup_commit(r, &head)) ||
-           parse_commit(commit) || get_message(commit, &message))
+           repo_parse_commit(r, commit) || get_message(commit, &message))
                fprintf(stderr, _("Stopped at HEAD\n"));
        else {
                fprintf(stderr, _("Stopped at %s\n"), message.label);
@@ -4628,6 +4656,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(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)
@@ -4643,12 +4733,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) {
@@ -4666,10 +4761,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);
@@ -4681,66 +4773,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 &&
-                                   !get_oid("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;
@@ -4788,22 +4824,19 @@ 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)) {
@@ -4820,7 +4853,7 @@ static int pick_commits(struct repository *r,
                        struct object_id head, orig;
                        int res;
 
-                       if (get_oid("HEAD", &head)) {
+                       if (repo_get_oid(r, "HEAD", &head)) {
                                res = error(_("cannot read HEAD"));
 cleanup_head_ref:
                                strbuf_release(&head_ref);
@@ -4867,8 +4900,8 @@ cleanup_head_ref:
                        log_tree_opt.disable_stdin = 1;
 
                        if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
-                           !get_oid(buf.buf, &orig) &&
-                           !get_oid("HEAD", &head)) {
+                           !repo_get_oid(r, buf.buf, &orig) &&
+                           !repo_get_oid(r, "HEAD", &head)) {
                                diff_tree_oid(&orig, &head, "",
                                              &log_tree_opt.diffopt);
                                log_tree_diff_flush(&log_tree_opt);
@@ -4956,11 +4989,16 @@ 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;
 
-               if (get_oid("HEAD", &head))
+               if (repo_get_oid(r, "HEAD", &head))
                        return error(_("cannot amend non-existing commit"));
                if (!read_oneliner(&rev, rebase_path_amend(), 0))
                        return error(_("invalid file: '%s'"), rebase_path_amend());
@@ -5035,18 +5073,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 = logmsg_reencode(commit, NULL, encoding)) ||
-                                   write_message(p, strlen(p), path, 0)) {
-                                       unuse_commit_buffer(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;
                                }
-                               unuse_commit_buffer(commit, p);
+                       unuse_commit_buffer:
+                               repo_unuse_commit_buffer(r, commit, p);
+                               if (res)
+                                       return res;
                        }
                }
 
@@ -5185,7 +5236,7 @@ int sequencer_pick_revisions(struct repository *r,
                if (!strlen(name))
                        continue;
 
-               if (!get_oid(name, &oid)) {
+               if (!repo_get_oid(r, name, &oid)) {
                        if (!lookup_commit_reference_gently(r, &oid, 1)) {
                                enum object_type type = oid_object_info(r,
                                                                        &oid,
@@ -5228,7 +5279,7 @@ int sequencer_pick_revisions(struct repository *r,
        if (walk_revs_populate_todo(&todo_list, opts) ||
                        create_seq_dir(r) < 0)
                return -1;
-       if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
+       if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
                return error(_("can't revert as initial commit"));
        if (save_head(oid_to_hex(&oid)))
                return -1;
@@ -5326,6 +5377,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,
@@ -5344,7 +5396,7 @@ static const char *label_oid(struct object_id *oid, const char *label,
         * For "uninteresting" commits, i.e. commits that are not to be
         * rebased, and which can therefore not be labeled, we use a unique
         * abbreviation of the commit name. This is slightly more complicated
-        * than calling find_unique_abbrev() because we also need to make
+        * than calling repo_find_unique_abbrev() because we also need to make
         * sure that the abbreviation does not conflict with any other
         * label.
         *
@@ -5360,7 +5412,8 @@ static const char *label_oid(struct object_id *oid, const char *label,
                strbuf_grow(&state->buf, GIT_MAX_HEXSZ);
                label = p = state->buf.buf;
 
-               find_unique_abbrev_r(p, oid, default_abbrev);
+               repo_find_unique_abbrev_r(the_repository, p, oid,
+                                         default_abbrev);
 
                /*
                 * We may need to extend the abbreviated hash so that there is
@@ -5381,6 +5434,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
@@ -5389,14 +5444,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-");
@@ -5458,7 +5533,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",
@@ -5466,6 +5542,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);
@@ -5922,7 +6000,7 @@ static int skip_unnecessary_picks(struct repository *r,
                        continue;
                if (item->command != TODO_PICK)
                        break;
-               if (parse_commit(item->commit)) {
+               if (repo_parse_commit(r, item->commit)) {
                        return error(_("could not parse commit '%s'"),
                                oid_to_hex(&item->commit->object.oid));
                }
@@ -6093,7 +6171,8 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
        struct object_id oid = onto->object.oid;
        int res;
 
-       find_unique_abbrev_r(shortonto, &oid, DEFAULT_ABBREV);
+       repo_find_unique_abbrev_r(r, shortonto, &oid,
+                                 DEFAULT_ABBREV);
 
        if (buf->len == 0) {
                struct todo_item *item = append_new_todo(todo_list);
@@ -6144,7 +6223,8 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
        todo_list_to_strbuf(r, &new_todo, &buf2, -1, 0);
        strbuf_swap(&new_todo.buf, &buf2);
        strbuf_release(&buf2);
-       new_todo.total_nr -= new_todo.nr;
+       /* Nothing is done yet, and we're reparsing, so let's reset the count */
+       new_todo.total_nr = 0;
        if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0)
                BUG("invalid todo list after expanding IDs:\n%s",
                    new_todo.buf.buf);
@@ -6165,7 +6245,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);
@@ -6254,12 +6334,15 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
                        return error(_("the script was already rearranged."));
                }
 
-               parse_commit(item->commit);
-               commit_buffer = logmsg_reencode(item->commit, NULL, "UTF-8");
+               repo_parse_commit(the_repository, item->commit);
+               commit_buffer = repo_logmsg_reencode(the_repository,
+                                                    item->commit, NULL,
+                                                    "UTF-8");
                find_commit_subject(commit_buffer, &subject);
                format_subject(&buf, subject, " ");
                subject = subjects[i] = strbuf_detach(&buf, &subject_len);
-               unuse_commit_buffer(item->commit, commit_buffer);
+               repo_unuse_commit_buffer(the_repository, item->commit,
+                                        commit_buffer);
                if (skip_fixupish(subject, &p)) {
                        struct commit *commit2;
 
@@ -6369,8 +6452,8 @@ int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
                if (file_exists(git_path_seq_dir()))
                        *whence = FROM_CHERRY_PICK_MULTI;
                if (file_exists(rebase_path()) &&
-                   !get_oid("REBASE_HEAD", &rebase_head) &&
-                   !get_oid("CHERRY_PICK_HEAD", &cherry_pick_head) &&
+                   !repo_get_oid(r, "REBASE_HEAD", &rebase_head) &&
+                   !repo_get_oid(r, "CHERRY_PICK_HEAD", &cherry_pick_head) &&
                    oideq(&rebase_head, &cherry_pick_head))
                        *whence = FROM_REBASE_PICK;
                else
index 3bcdfa1b5865fc5209141870076b7325edfa36d4..913a0f652d9ab356bc066f162fa1e5197f6900eb 100644 (file)
@@ -1,11 +1,12 @@
 #ifndef SEQUENCER_H
 #define SEQUENCER_H
 
-#include "cache.h"
 #include "strbuf.h"
+#include "strvec.h"
 #include "wt-status.h"
 
 struct commit;
+struct index_state;
 struct repository;
 
 const char *git_path_commit_editmsg(void);
@@ -60,8 +61,7 @@ struct replay_opts {
        /* Merge strategy */
        char *default_strategy;  /* from config options */
        char *strategy;
-       char **xopts;
-       size_t xopts_nr, xopts_alloc;
+       struct strvec xopts;
 
        /* Reflog */
        char *reflog_action;
@@ -80,7 +80,12 @@ struct replay_opts {
        /* Private use */
        const char *reflog_message;
 };
-#define REPLAY_OPTS_INIT { .edit = -1, .action = -1, .current_fixups = STRBUF_INIT }
+#define REPLAY_OPTS_INIT {                     \
+       .edit = -1,                             \
+       .action = -1,                           \
+       .current_fixups = STRBUF_INIT,          \
+       .xopts = STRVEC_INIT,                   \
+}
 
 /*
  * Note that ordering matters in this enum. Not only must it match the mapping
@@ -247,7 +252,6 @@ int read_oneliner(struct strbuf *buf,
        const char *path, unsigned flags);
 int read_author_script(const char *path, char **name, char **email, char **date,
                       int allow_missing);
-void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
 int write_basic_state(struct replay_opts *opts, const char *head_name,
                      struct commit *onto, const struct object_id *orig_head);
 void sequencer_post_commit_cleanup(struct repository *r, int verbose);
diff --git a/serve.c b/serve.c
index cbf4a143cfea9bd450d5d033b1ec051025af8a1f..a1d71134d49cc88ead5af690315b27ae23215e56 100644 (file)
--- a/serve.c
+++ b/serve.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#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"
@@ -8,17 +9,18 @@
 #include "serve.h"
 #include "upload-pack.h"
 #include "bundle-uri.h"
+#include "trace2.h"
 
 static int advertise_sid = -1;
 static int client_hash_algo = GIT_HASH_SHA1;
 
-static int always_advertise(struct repository *r,
-                           struct strbuf *value)
+static int always_advertise(struct repository *r UNUSED,
+                           struct strbuf *value UNUSED)
 {
        return 1;
 }
 
-static int agent_advertise(struct repository *r,
+static int agent_advertise(struct repository *r UNUSED,
                           struct strbuf *value)
 {
        if (value)
@@ -34,7 +36,7 @@ static int object_format_advertise(struct repository *r,
        return 1;
 }
 
-static void object_format_receive(struct repository *r,
+static void object_format_receive(struct repository *r UNUSED,
                                  const char *algo_name)
 {
        if (!algo_name)
@@ -48,7 +50,7 @@ static void object_format_receive(struct repository *r,
 static int session_id_advertise(struct repository *r, struct strbuf *value)
 {
        if (advertise_sid == -1 &&
-           git_config_get_bool("transfer.advertisesid", &advertise_sid))
+           repo_config_get_bool(r, "transfer.advertisesid", &advertise_sid))
                advertise_sid = 0;
        if (!advertise_sid)
                return 0;
@@ -57,7 +59,7 @@ static int session_id_advertise(struct repository *r, struct strbuf *value)
        return 1;
 }
 
-static void session_id_receive(struct repository *r,
+static void session_id_receive(struct repository *r UNUSED,
                               const char *client_sid)
 {
        if (!client_sid)
index 0ec6c0c16546a7a2ebb45a8e8a03e3270cedf214..e2fe0f91432d8089e74c7e562728aca329dec66c 100644 (file)
@@ -1,12 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "dir.h"
+#include "environment.h"
+#include "hex.h"
 #include "repository.h"
 #include "refs.h"
 #include "object.h"
 #include "commit.h"
 #include "tag.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "path.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "server-info.h"
 #include "strbuf.h"
 
 struct update_info_ctx {
diff --git a/server-info.h b/server-info.h
new file mode 100644 (file)
index 0000000..13bbde2
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef SERVER_INFO_H
+#define SERVER_INFO_H
+
+/* Dumb servers support */
+int update_server_info(int);
+
+#endif /* SERVER_INFO_H */
diff --git a/setup.c b/setup.c
index cefd5f63c4680f7f656084ef72f74784f86e4562..2e607632dbde807ae76566e282d8f122b1642cda 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1,11 +1,22 @@
-#include "cache.h"
+#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 "worktree.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -510,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;
 
@@ -581,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:
@@ -610,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)
@@ -643,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
@@ -1109,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;
 
@@ -1165,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;
 
@@ -1205,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.
@@ -1345,6 +1348,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
                }
 
                if (is_git_directory(dir->buf)) {
+                       trace2_data_string("setup", NULL, "implicit-bare-repository", dir->buf);
                        if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
                                return GIT_DIR_DISALLOWED_BARE;
                        if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
@@ -1368,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;
        }
 
        /*
@@ -1412,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)
@@ -1503,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.
                 */
@@ -1552,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;
@@ -1643,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);
@@ -1699,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
new file mode 100644 (file)
index 0000000..b48cf1c
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,206 @@
+#ifndef SETUP_H
+#define SETUP_H
+
+#include "string-list.h"
+
+int is_inside_git_dir(void);
+int is_inside_work_tree(void);
+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
+int get_common_dir(struct strbuf *sb, const char *gitdir);
+
+/*
+ * Return true if the given path is a git directory; note that this _just_
+ * looks at the directory itself. If you want to know whether "foo/.git"
+ * is a repository, you must feed that path, not just "foo".
+ */
+int is_git_directory(const char *path);
+
+/*
+ * Return 1 if the given path is the root of a git repository or
+ * submodule, else 0. Will not return 1 for bare repositories with the
+ * exception of creating a bare repository in "foo/.git" and calling
+ * is_git_repository("foo").
+ *
+ * If we run into read errors, we err on the side of saying "yes, it is",
+ * as we usually consider sub-repos precious, and would prefer to err on the
+ * side of not disrupting or deleting them.
+ */
+int is_nonbare_repository_dir(struct strbuf *path);
+
+#define READ_GITFILE_ERR_STAT_FAILED 1
+#define READ_GITFILE_ERR_NOT_A_FILE 2
+#define READ_GITFILE_ERR_OPEN_FAILED 3
+#define READ_GITFILE_ERR_READ_FAILED 4
+#define READ_GITFILE_ERR_INVALID_FORMAT 5
+#define READ_GITFILE_ERR_NO_PATH 6
+#define READ_GITFILE_ERR_NOT_A_REPO 7
+#define READ_GITFILE_ERR_TOO_LARGE 8
+void read_gitfile_error_die(int error_code, const char *path, const char *dir);
+const char *read_gitfile_gently(const char *path, int *return_error_code);
+#define read_gitfile(path) read_gitfile_gently((path), NULL)
+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 -1 if no repository was found.
+ */
+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);
+char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
+
+int check_filename(const char *prefix, const char *name);
+void verify_filename(const char *prefix,
+                    const char *name,
+                    int diagnose_misspelt_rev);
+void verify_non_filename(const char *prefix, const char *name);
+int path_inside_repo(const char *prefix, const char *path);
+
+void sanitize_stdfds(void);
+int daemonize(void);
+
+/*
+ * GIT_REPO_VERSION is the version we write by default. The
+ * _READ variant is the highest number we know how to
+ * handle.
+ */
+#define GIT_REPO_VERSION 0
+#define GIT_REPO_VERSION_READ 1
+
+/*
+ * You _have_ to initialize a `struct repository_format` using
+ * `= REPOSITORY_FORMAT_INIT` before calling `read_repository_format()`.
+ */
+struct repository_format {
+       int version;
+       int precious_objects;
+       char *partial_clone; /* value of extensions.partialclone */
+       int worktree_config;
+       int is_bare;
+       int hash_algo;
+       int sparse_index;
+       char *work_tree;
+       struct string_list unknown_extensions;
+       struct string_list v1_only_extensions;
+};
+
+/*
+ * Always use this to initialize a `struct repository_format`
+ * to a well-defined, default state before calling
+ * `read_repository()`.
+ */
+#define REPOSITORY_FORMAT_INIT \
+{ \
+       .version = -1, \
+       .is_bare = -1, \
+       .hash_algo = GIT_HASH_SHA1, \
+       .unknown_extensions = STRING_LIST_INIT_DUP, \
+       .v1_only_extensions = STRING_LIST_INIT_DUP, \
+}
+
+/*
+ * Read the repository format characteristics from the config file "path" into
+ * "format" struct. Returns the numeric version. On error, or if no version is
+ * found in the configuration, -1 is returned, format->version is set to -1,
+ * and all other fields in the struct are set to the default configuration
+ * (REPOSITORY_FORMAT_INIT). Always initialize the struct using
+ * REPOSITORY_FORMAT_INIT before calling this function.
+ */
+int read_repository_format(struct repository_format *format, const char *path);
+
+/*
+ * Free the memory held onto by `format`, but not the struct itself.
+ * (No need to use this after `read_repository_format()` fails.)
+ */
+void clear_repository_format(struct repository_format *format);
+
+/*
+ * Verify that the repository described by repository_format is something we
+ * can read. If it is, return 0. Otherwise, return -1, and "err" will describe
+ * any errors encountered.
+ */
+int verify_repository_format(const struct repository_format *format,
+                            struct strbuf *err);
+
+/*
+ * Check the repository format version in the path found in get_git_dir(),
+ * and die if it is a version we don't understand. Generally one would
+ * set_git_dir() before calling this, and use it only for "are we in a valid
+ * repo?".
+ *
+ * If successful and fmt is not NULL, fill fmt with data.
+ */
+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!!
+ *
+ * PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
+ * not be changed. Old repositories have core.sharedrepository written in
+ * numeric format, and therefore these values are preserved for compatibility
+ * reasons.
+ */
+enum sharedrepo {
+       PERM_UMASK          = 0,
+       OLD_PERM_GROUP      = 1,
+       OLD_PERM_EVERYBODY  = 2,
+       PERM_GROUP          = 0660,
+       PERM_EVERYBODY      = 0664
+};
+int git_config_perm(const char *var, const char *value);
+
+struct startup_info {
+       int have_repository;
+       const char *prefix;
+       const char *original_cwd;
+};
+extern struct startup_info *startup_info;
+extern const char *tmp_original_cwd;
+
+#endif /* SETUP_H */
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 5c300e812e0a11960dba743773720246e1a84cf1..9b675a046ee699189f54e31cf9a4e8bfc6d304a6 100644 (file)
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "sha1dc_git.h"
+#include "hex.h"
 
 #ifdef DC_SHA1_EXTERNAL
 /*
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 17f9bcdb5f38270c4f5910a2e1c930432ba350e5..5413719fd4ef16c130117440c4d4687f9c1c5525 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -1,20 +1,24 @@
-#include "cache.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"
 
 void set_alternate_shallow_file(struct repository *r, const char *path, int override)
 {
@@ -30,7 +34,7 @@ int register_shallow(struct repository *r, const struct object_id *oid)
 {
        struct commit_graft *graft =
                xmalloc(sizeof(struct commit_graft));
-       struct commit *commit = lookup_commit(the_repository, oid);
+       struct commit *commit = lookup_commit(r, oid);
 
        oidcpy(&graft->oid, oid);
        graft->nr_parent = -1;
@@ -247,7 +251,7 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,
                struct commit *c = p->item;
                struct commit_list *parent;
 
-               if (parse_commit(c))
+               if (repo_parse_commit(the_repository, c))
                        die("unable to parse commit %s",
                            oid_to_hex(&c->object.oid));
 
@@ -301,7 +305,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
        if (graft->nr_parent != -1)
                return 0;
        if (data->flags & QUICK) {
-               if (!has_object_file(&graft->oid))
+               if (!repo_has_object_file(the_repository, &graft->oid))
                        return 0;
        } else if (data->flags & SEEN_ONLY) {
                struct commit *c = lookup_commit(the_repository, &graft->oid);
@@ -466,7 +470,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
        ALLOC_ARRAY(info->ours, sa->nr);
        ALLOC_ARRAY(info->theirs, sa->nr);
        for (i = 0; i < sa->nr; i++) {
-               if (has_object_file(sa->oid + i)) {
+               if (repo_has_object_file(the_repository, sa->oid + i)) {
                        struct commit_graft *graft;
                        graft = lookup_commit_graft(the_repository,
                                                    &sa->oid[i]);
@@ -494,7 +498,7 @@ void remove_nonexistent_theirs_shallow(struct shallow_info *info)
        for (i = dst = 0; i < info->nr_theirs; i++) {
                if (i != dst)
                        info->theirs[dst] = info->theirs[i];
-               if (has_object_file(oid + info->theirs[i]))
+               if (repo_has_object_file(the_repository, oid + info->theirs[i]))
                        dst++;
        }
        info->nr_theirs = dst;
@@ -583,7 +587,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
                if (c->object.flags & BOTTOM)
                        continue;
 
-               if (parse_commit(c))
+               if (repo_parse_commit(the_repository, c))
                        die("unable to parse commit %s",
                            oid_to_hex(&c->object.oid));
 
@@ -791,7 +795,7 @@ static void post_assign_shallow(struct shallow_info *info,
                for (j = 0; j < bitmap_nr; j++)
                        if (bitmap[0][j] &&
                            /* Step 7, reachability test at commit level */
-                           !in_merge_bases_many(c, ca.nr, ca.commits)) {
+                           !repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits)) {
                                update_refstatus(ref_status, info->ref->nr, *bitmap);
                                dst++;
                                break;
@@ -819,9 +823,10 @@ int delayed_reachability_test(struct shallow_info *si, int c)
                        si->nr_commits = ca.nr;
                }
 
-               si->reachable[c] = in_merge_bases_many(commit,
-                                                      si->nr_commits,
-                                                      si->commits);
+               si->reachable[c] = repo_in_merge_bases_many(the_repository,
+                                                           commit,
+                                                           si->nr_commits,
+                                                           si->commits);
                si->need_reachability_test[c] = 0;
        }
        return si->reachable[c];
index aba6ff5829405647070c5b2a475318e2fd76282d..e9ca7e4bc80451a74dc10fb6d4e1a0b190dc4dcc 100644 (file)
--- a/shallow.h
+++ b/shallow.h
@@ -6,6 +6,8 @@
 #include "repository.h"
 #include "strbuf.h"
 
+struct oid_array;
+
 void set_alternate_shallow_file(struct repository *r, const char *path, int override);
 int register_shallow(struct repository *r, const struct object_id *oid);
 int unregister_shallow(const struct object_id *oid);
diff --git a/shell.c b/shell.c
index af0d7c734f8347082ab094cf1fc8898cbf26b64d..5c67e7bd97e2c825d79c3503267b5b41cd83bb8a 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "quote.h"
 #include "exec-cmd.h"
 #include "strbuf.h"
index 85bddfdcd4f57a37be390d424d3628d1f34877a7..6cbfd391c47fb531740eb4b963a11b77f8abe29d 100644 (file)
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "color.h"
 #include "config.h"
+#include "editor.h"
+#include "gettext.h"
 #include "sideband.h"
 #include "help.h"
 #include "pkt-line.h"
+#include "write-or-die.h"
 
 struct keyword_entry {
        /*
index 022677b6abaf918f51804a8fcbf18776aa3f2be5..66123bdbabb04123c6f0f4b64a8262584e3d2555 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "sigchain.h"
 
 #define SIGCHAIN_MAX_SIGNALS 32
index 147a13386a445b7278b87c5072d7d5c308a35b8f..1fdb07a9e69be2db0b03d283f0f100a1d2842ad2 100644 (file)
@@ -1,4 +1,8 @@
-#include "cache.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"
@@ -7,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;
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 5d0f04763ea2d201a3bbe417bd1951aea23a8436..8c38687c04b81ceaa57746a96daf670874e31643 100644 (file)
@@ -1,5 +1,10 @@
-#include "cache.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"
 
 struct split_index *init_split_index(struct index_state *istate)
index 7a435ca2c970111b40ac9edba65726e79bd7941d..15a29cd08c96be6eeff23f609ec7c8d9533175b1 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef SPLIT_INDEX_H
 #define SPLIT_INDEX_H
 
-#include "cache.h"
+#include "hash-ll.h"
 
 struct index_state;
 struct strbuf;
diff --git a/statinfo.c b/statinfo.c
new file mode 100644 (file)
index 0000000..17bb896
--- /dev/null
@@ -0,0 +1,87 @@
+#include "git-compat-util.h"
+#include "environment.h"
+#include "statinfo.h"
+
+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;
+}
+
+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);
+       }
+}
diff --git a/statinfo.h b/statinfo.h
new file mode 100644 (file)
index 0000000..700f502
--- /dev/null
@@ -0,0 +1,89 @@
+#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
+ * check it for equality in the 32 bits we save.
+ */
+struct cache_time {
+       uint32_t sec;
+       uint32_t nsec;
+};
+
+struct stat_data {
+       struct cache_time sd_ctime;
+       struct cache_time sd_mtime;
+       unsigned int sd_dev;
+       unsigned int sd_ino;
+       unsigned int sd_uid;
+       unsigned int sd_gid;
+       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 c383f41a3c5ccc6c6228c4ed4f9631529633f878..4c9ac6dc5e3cd34fd059ca3a20f8e98bd08b2d4a 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,5 +1,7 @@
-#include "cache.h"
-#include "refs.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "strbuf.h"
 #include "string-list.h"
 #include "utf8.h"
 #include "date.h"
@@ -357,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];
@@ -369,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;
@@ -379,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';
 
@@ -407,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;
-
-               if (*format == '%') {
-                       strbuf_addch(sb, '%');
-                       format++;
-                       continue;
-               }
+       const char *format = *formatp;
+       const char *percent = strchrnul(format, '%');
 
-               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;
 
@@ -455,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;
@@ -713,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);
@@ -725,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');
@@ -803,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)
 {
@@ -892,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;
@@ -1014,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;
 
@@ -1072,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.
  *
@@ -1116,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;
@@ -1132,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;
                }
@@ -1153,54 +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;
-}
-
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
-                             const char *const *env)
-{
-       char *path2 = NULL;
-       int fd, res = 0;
-
-       if (!is_absolute_path(path))
-               path = path2 = xstrdup(git_path("%s", path));
-
-       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-       if (fd < 0)
-               res = error_errno(_("could not open '%s' for writing"), path);
-       else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
-               res = error_errno(_("could not write to '%s'"), path);
-               close(fd);
-       } else if (close(fd) < 0)
-               res = error_errno(_("could not close '%s'"), path);
-       else {
-               strbuf_reset(buffer);
-               if (launch_editor(path, buffer, env) < 0)
-                       res = error_errno(_("could not edit '%s'"), path);
-               unlink(path);
-       }
-
-       free(path2);
-       return res;
-}
-
 void strbuf_strip_file_from_path(struct strbuf *sb)
 {
        char *path_sep = find_last_dir_sep(sb->buf);
index f6dbb9681ee768221e707a39c37dc0a00f63b95d..fd43c46433a4b938f3c46a634db740b4c352a475 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,6 +1,14 @@
 #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;
 
 /**
@@ -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.
- */
-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);
-
-/**
- * Used as callback for `strbuf_expand` to only expand literals
- * (i.e. %n and %xNN). The context argument is ignored.
+ * Used with `strbuf_expand_step` to expand the literals %n and %x
+ * followed by two hexadecimal digits. Returns the number of recognized
+ * characters.
  */
-size_t strbuf_expand_literal_cb(struct strbuf *sb,
-                               const char *placeholder,
-                               void *context);
+size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder);
 
 /**
- * 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.
+ * 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.
  */
-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,40 +587,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,
  */
 void strbuf_list_free(struct strbuf **list);
 
-/**
- * Add the abbreviation, as generated by 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);
-
-/**
- * Launch the user preferred editor to edit a file and fill the buffer
- * with the file's contents upon the user completing their editing. The
- * third argument can be used to set the environment which the editor is
- * run in. If the buffer is NULL the editor is launched as usual but the
- * file's contents are not read into the buffer upon completion.
- */
-int launch_editor(const char *path, struct strbuf *buffer,
-                 const char *const *env);
-
-int launch_sequence_editor(const char *path, struct strbuf *buffer,
-                          const char *const *env);
-
-/*
- * In contrast to `launch_editor()`, this function writes out the contents
- * of the specified file first, then clears the `buffer`, then launches
- * the editor and reads back in the file contents into the `buffer`.
- * Finally, it deletes the temporary file.
- *
- * If `path` is relative, it refers to a file in the `.git` directory.
- */
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
-                             const char *const *env);
-
 /*
  * Remove the filename from the provided path string. If the path
  * contains a trailing separator, then the path is considered a directory
@@ -706,14 +629,14 @@ static inline void strbuf_complete_line(struct strbuf *sb)
 
 /*
  * Copy "name" to "sb", expanding any special @-marks as handled by
- * interpret_branch_name(). The result is a non-qualified branch name
+ * repo_interpret_branch_name(). The result is a non-qualified branch name
  * (so "foo" or "origin/master" instead of "refs/heads/foo" or
  * "refs/remotes/origin/master").
  *
  * Note that the resulting name may not be a syntactically valid refname.
  *
  * If "allowed" is non-zero, restrict the set of allowed expansions. See
- * interpret_branch_name() for details.
+ * repo_interpret_branch_name() for details.
  */
 void strbuf_branchname(struct strbuf *sb, const char *name,
                       unsigned allowed);
@@ -728,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);
 
@@ -751,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 27841dc1d9e535df291a1005a7a005d65323dd1d..10adf625b2e7ab23ffde1c8c826f6c10691792d8 100644 (file)
@@ -1,10 +1,13 @@
 /*
  * Copyright (c) 2011, Google Inc.
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "convert.h"
+#include "environment.h"
 #include "streaming.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
 #include "replace-object.h"
 #include "packfile.h"
 
index 5e4e6acfd0dc947bcb92680fbae71de1fc486a78..bd27f59e5764aec64cd1cf927baf213fcec4d893 100644 (file)
@@ -3,10 +3,12 @@
  */
 #ifndef STREAMING_H
 #define STREAMING_H 1
-#include "cache.h"
+
+#include "object.h"
 
 /* opaque */
 struct git_istream;
+struct stream_filter;
 
 struct git_istream *open_istream(struct repository *, const struct object_id *,
                                 enum object_type *, unsigned long *,
index 42bacaec55b6ca6bf885797c1c76fc6e964ddfbd..954569f381d8d7ea2e1c6f1333b1e8379ffe2fe8 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "string-list.h"
 
 void string_list_init_nodup(struct string_list *list)
@@ -202,6 +202,15 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
        list->nr = list->alloc = 0;
 }
 
+void string_list_setlen(struct string_list *list, size_t nr)
+{
+       if (list->strdup_strings)
+               BUG("cannot setlen a string_list which owns its entries");
+       if (nr > list->nr)
+               BUG("cannot grow a string_list with setlen");
+       list->nr = nr;
+}
+
 struct string_list_item *string_list_append_nodup(struct string_list *list,
                                                  char *string)
 {
@@ -300,7 +309,7 @@ int string_list_split(struct string_list *list, const char *string,
 }
 
 int string_list_split_in_place(struct string_list *list, char *string,
-                              int delim, int maxsplit)
+                              const char *delim, int maxsplit)
 {
        int count = 0;
        char *p = string, *end;
@@ -314,7 +323,7 @@ int string_list_split_in_place(struct string_list *list, char *string,
                        string_list_append(list, p);
                        return count;
                }
-               end = strchr(p, delim);
+               end = strpbrk(p, delim);
                if (end) {
                        *end = '\0';
                        string_list_append(list, p);
index c7b0d5d0008efb906ba034c632adb69b53c4f545..122b3186419880403da702c928724aaefd8e34f3 100644 (file)
@@ -134,6 +134,16 @@ typedef void (*string_list_clear_func_t)(void *p, const char *str);
 /** Call a custom clear function on each util pointer */
 void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);
 
+/*
+ * Set the length of a string_list to `nr`, provided that (a) `list`
+ * does not own its own storage, and (b) that `nr` is no larger than
+ * `list->nr`.
+ *
+ * Useful when "shrinking" `list` to write over existing entries that
+ * are no longer used without reallocating.
+ */
+void string_list_setlen(struct string_list *list, size_t nr);
+
 /**
  * Apply `func` to each item. If `func` returns nonzero, the
  * iteration aborts and the return value is propagated.
@@ -270,5 +280,5 @@ int string_list_split(struct string_list *list, const char *string,
  * list->strdup_strings must *not* be set.
  */
 int string_list_split_in_place(struct string_list *list, char *string,
-                              int delim, int maxsplit);
+                              const char *delim, int maxsplit);
 #endif /* STRING_LIST_H */
index 61a76ce6cb920f33744e82111c800da8439ed975..89dc9e7e753313acbb0a5dc83b7705f3538a4c45 100644 (file)
--- a/strvec.c
+++ b/strvec.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "strvec.h"
+#include "hex.h"
 #include "strbuf.h"
 
 const char *empty_strvec[] = { NULL };
index 6d4232294dbee7ad2928b0ac12e1860dcf04a12d..1daf5a975254b9b9ea286c5486f4d07f3874bb26 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Generic implementation of background process infrastructure.
  */
+#include "git-compat-util.h"
 #include "sub-process.h"
 #include "sigchain.h"
 #include "pkt-line.h"
index e85f21fa1a7c2bc59f032b5b2a2cffd6cab771a5..6a61638a8ace0b760e1254bcbea14061c3843a25 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef SUBPROCESS_H
 #define SUBPROCESS_H
 
-#include "git-compat-util.h"
 #include "hashmap.h"
 #include "run-command.h"
 
index 4dc61b3a78a2916d737edf613af0f9c0e03d39c8..6a48fd12f66f93d132aab6745d67effd482a168f 100644 (file)
@@ -1,12 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.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-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "parse-options.h"
+#include "thread-utils.h"
 #include "tree-walk.h"
 
 /*
@@ -298,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)
@@ -420,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;
@@ -535,7 +543,7 @@ static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
        }
 
        strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
-       if (get_oid(rev->buf, gitmodules_oid) >= 0)
+       if (repo_get_oid(the_repository, rev->buf, gitmodules_oid) >= 0)
                ret = 1;
 
        return ret;
@@ -588,7 +596,8 @@ static const struct submodule *config_from(struct submodule_cache *cache,
        if (submodule)
                goto out;
 
-       config = read_object_file(&oid, &type, &config_size);
+       config = repo_read_object_file(the_repository, &oid, &type,
+                                      &config_size);
        if (!config || type != OBJ_BLOB)
                goto out;
 
@@ -598,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);
 
@@ -652,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);
@@ -660,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);
@@ -668,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;
@@ -678,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)
@@ -706,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);
 
@@ -795,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;
 
@@ -837,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)
@@ -865,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 28a8ca6bf46845906cb4bc2071a594a383eefc72..2a37689cc272e30fa6f5dc9cfbbde044a52068c3 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef SUBMODULE_CONFIG_CACHE_H
 #define SUBMODULE_CONFIG_CACHE_H
 
-#include "cache.h"
 #include "config.h"
 #include "hashmap.h"
 #include "submodule.h"
@@ -51,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 3a0dfc417c05b627a5100f518768a1b32ee22339..e603a19a876c88c59f18da33caa1541b15ded9f3 100644 (file)
@@ -1,5 +1,5 @@
-
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "repository.h"
 #include "config.h"
 #include "submodule-config.h"
@@ -7,6 +7,9 @@
 #include "dir.h"
 #include "diff.h"
 #include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "revision.h"
 #include "run-command.h"
 #include "diffcore.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-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "commit-reach.h"
+#include "read-cache-ll.h"
+#include "setup.h"
 #include "shallow.h"
+#include "trace2.h"
 
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
 static int initialized_fetch_ref_tips;
@@ -65,7 +74,7 @@ int is_writing_gitmodules_ok(void)
 {
        struct object_id oid;
        return file_exists(GITMODULES_FILE) ||
-               (get_oid(GITMODULES_INDEX, &oid) < 0 && get_oid(GITMODULES_HEAD, &oid) < 0);
+               (repo_get_oid(the_repository, GITMODULES_INDEX, &oid) < 0 && repo_get_oid(the_repository, GITMODULES_HEAD, &oid) < 0);
 }
 
 /*
@@ -274,8 +283,7 @@ int is_tree_submodule_active(struct repository *repo,
        free(key);
 
        /* submodule.active is set */
-       sl = repo_config_get_value_multi(repo, "submodule.active");
-       if (sl) {
+       if (!repo_config_get_string_multi(repo, "submodule.active", &sl)) {
                struct pathspec ps;
                struct strvec args = STRVEC_INIT;
                const struct string_list_item *item;
@@ -1625,7 +1633,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
                if (!task->repo) {
                        strbuf_addf(err, _("Could not access submodule '%s' at commit %s\n"),
                                    cs_data->path,
-                                   find_unique_abbrev(cs_data->super_oid, DEFAULT_ABBREV));
+                                   repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV));
 
                        fetch_task_release(task);
                        free(task);
@@ -1636,8 +1644,8 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
                        strbuf_addf(err,
                                    _("Fetching submodule %s%s at commit %s\n"),
                                    spf->prefix, task->sub->path,
-                                   find_unique_abbrev(cs_data->super_oid,
-                                                      DEFAULT_ABBREV));
+                                   repo_find_unique_abbrev(the_repository, cs_data->super_oid,
+                                                           DEFAULT_ABBREV));
 
                spf->changed_count++;
                /*
@@ -1739,7 +1747,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
        return 0;
 }
 
-static int fetch_start_failure(struct strbuf *err,
+static int fetch_start_failure(struct strbuf *err UNUSED,
                               void *cb, void *task_cb)
 {
        struct submodule_parallel_fetch *spf = cb;
@@ -1760,7 +1768,7 @@ static int commit_missing_in_sub(const struct object_id *oid, void *data)
        return type != OBJ_COMMIT;
 }
 
-static int fetch_finish(int retvalue, struct strbuf *err,
+static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
                        void *cb, void *task_cb)
 {
        struct submodule_parallel_fetch *spf = cb;
index c667baa949b685c6c78c41eb8d272410c7574fe4..b29e340c2da43e9ac35adcda05322b1e068017ca 100644 (file)
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "setup.h"
+#include "symlinks.h"
 
 static int threaded_check_leading_path(struct cache_def *cache, const char *name,
                                       int len, int warn_on_lstat_err);
diff --git a/symlinks.h b/symlinks.h
new file mode 100644 (file)
index 0000000..7ae3d5b
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef SYMLINKS_H
+#define SYMLINKS_H
+
+#include "strbuf.h"
+
+struct cache_def {
+       struct strbuf path;
+       int flags;
+       int track_flags;
+       int prefix_len_stat_func;
+};
+#define CACHE_DEF_INIT { \
+       .path = STRBUF_INIT, \
+}
+static inline void cache_def_clear(struct cache_def *cache)
+{
+       strbuf_release(&cache->path);
+}
+
+int has_symlink_leading_path(const char *name, int len);
+int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
+int check_leading_path(const char *name, int len, int warn_on_lstat_err);
+int has_dirs_only_path(const char *name, int len, int prefix_len);
+void invalidate_lstat_cache(void);
+void schedule_dir_for_removal(const char *name, int len);
+void remove_scheduled_dirs(void);
+
+#endif /* SYMLINKS_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 2c2b2522402d087bee89ae8c08be99449c893057..3e00cdd801d637388edf1a546f9613a99cd3c737 100644 (file)
@@ -44,8 +44,8 @@ CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl
 
 # `test-chainlint` (which is a dependency of `test-lint`, `test` and `prove`)
 # checks all tests in all scripts via a single invocation, so tell individual
-# scripts not to "chainlint" themselves
-CHAINLINTSUPPRESS = GIT_TEST_CHAIN_LINT=0 && export GIT_TEST_CHAIN_LINT &&
+# scripts not to run the external "chainlint.pl" script themselves
+CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT &&
 
 all: $(DEFAULT_TEST_TARGET)
 
@@ -140,9 +140,7 @@ aggregate-results-and-cleanup: $(T)
        $(MAKE) clean
 
 aggregate-results:
-       for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \
-               echo "$$f"; \
-       done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh
+       @'$(SHELL_PATH_SQ)' ./aggregate-results.sh '$(TEST_RESULTS_DIRECTORY_SQ)'
 
 valgrind:
        $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
index 29576c37488593d79978a50d405e107b25dbcc7c..61080859899bef0de95e04070ab54484bf591345 100644 (file)
--- a/t/README
+++ b/t/README
@@ -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.
@@ -475,7 +479,7 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to
 use in the test scripts. Recognized values for <hash-algo> are "sha1"
 and "sha256".
 
-GIT_TEST_WRITE_REV_INDEX=<boolean>, when true enables the
+GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the
 'pack.writeReverseIndex' setting.
 
 GIT_TEST_SPARSE_INDEX=<boolean>, when true enables index writes to use the
@@ -1098,6 +1102,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
index 7f2b83bdc8181f6d653f40bf99a40bf8e7cc03f5..6e3bcc4aec7cb922b9fc9ed4469c79b1699c76cc 100755 (executable)
@@ -8,7 +8,7 @@ broken=0
 total=0
 missing_prereq=
 
-while read file
+for file in "$1"/t*-*.counts
 do
        while read type value
        do
index f1b9a6ce4daee67c7aadfd2a9d19cb1c4033224c..5e21e84f3884eb8c787ab82a5d1360d2b7cffb74 100644 (file)
@@ -72,6 +72,32 @@ test_expect_success 'blame 1 author' '
        check_count A 2
 '
 
+test_expect_success 'blame working copy' '
+       test_when_finished "git restore file" &&
+       echo "1A quick brown fox jumps over the" >file &&
+       echo "another lazy dog" >>file &&
+       check_count A 1 "Not Committed Yet" 1
+'
+
+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 &&
+       check_count --contents=contents A 1 "External file (--contents)" 1
+'
+
 test_expect_success 'blame in a bare repo without starting commit' '
        git clone --bare . bare.git &&
        (
@@ -98,6 +124,10 @@ test_expect_success 'blame 2 authors' '
        check_count A 2 B 2
 '
 
+test_expect_success 'blame with --contents and revision' '
+       check_count -h testTag --contents=file A 2 "External file (--contents)" 2
+'
+
 test_expect_success 'setup B1 lines (branch1)' '
        git checkout -b branch1 main &&
        echo "3A slow green fox jumps into the" >>file &&
index e966412999ac9e4d7279505275ed1480e04f5b2a..556ee91a15b7c2124b42b0af8ef6481a787f5188 100755 (executable)
@@ -80,7 +80,8 @@ sub scan_heredoc_tag {
        return "<<$indented" unless $token;
        my $tag = $token->[0];
        $tag =~ s/['"\\]//g;
-       push(@{$self->{heretags}}, $indented ? "\t$tag" : "$tag");
+       $$token[0] = $indented ? "\t$tag" : "$tag";
+       push(@{$self->{heretags}}, $token);
        return "<<$indented$tag";
 }
 
@@ -169,10 +170,18 @@ sub swallow_heredocs {
        my $tags = $self->{heretags};
        while (my $tag = shift @$tags) {
                my $start = pos($$b);
-               my $indent = $tag =~ s/^\t// ? '\\s*' : '';
-               $$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc;
+               my $indent = $$tag[0] =~ s/^\t// ? '\\s*' : '';
+               $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc;
+               if (pos($$b) > $start) {
+                       my $body = substr($$b, $start, pos($$b) - $start);
+                       $self->{lineno} += () = $body =~ /\n/sg;
+                       next;
+               }
+               push(@{$self->{parser}->{problems}}, ['UNCLOSED-HEREDOC', $tag]);
+               $$b =~ /(?:\G|\n).*\z/gc; # consume rest of input
                my $body = substr($$b, $start, pos($$b) - $start);
                $self->{lineno} += () = $body =~ /\n/sg;
+               last;
        }
 }
 
diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect
new file mode 100644 (file)
index 0000000..7c30a1a
--- /dev/null
@@ -0,0 +1,4 @@
+command_which_is_run &&
+cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! &&
+we forget to end the here-doc
+command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test
new file mode 100644 (file)
index 0000000..5c841a9
--- /dev/null
@@ -0,0 +1,4 @@
+command_which_is_run &&
+cat >expect <<-\EOF &&
+we forget to end the here-doc
+command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect
new file mode 100644 (file)
index 0000000..d65e50f
--- /dev/null
@@ -0,0 +1,7 @@
+command_which_is_run &&
+cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! &&
+       we try to end the here-doc below,
+       but the indentation throws us off
+       since the operator is not "<<-".
+       EOF
+command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test
new file mode 100644 (file)
index 0000000..69d3786
--- /dev/null
@@ -0,0 +1,7 @@
+command_which_is_run &&
+cat >expect <<\EOF &&
+       we try to end the here-doc below,
+       but the indentation throws us off
+       since the operator is not "<<-".
+       EOF
+command_which_is_gobbled
index cb881139f7316f475ea072c1b549aafe7cca2ad1..8a3fd0009a042c67019a3e89e5727dc4b7240600 100644 (file)
@@ -1,7 +1,7 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "advice.h"
 #include "config.h"
+#include "setup.h"
 
 int cmd__advise_if_enabled(int argc, const char **argv)
 {
index ff35f5999b367106f04743582ca9fb490b80501f..af43ee1cb5ee27c6aad608c7a233e234a7146f89 100644 (file)
@@ -1,6 +1,7 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "git-compat-util.h"
 #include "pack-bitmap.h"
+#include "setup.h"
 
 static int bitmap_list_commits(void)
 {
index 6c900ca668467dcdbc92c6544ad173565c3a5f08..aabe31d724b675e4f69c9f3760bcd0a6e8e9bbad 100644 (file)
@@ -1,7 +1,9 @@
-#include "git-compat-util.h"
-#include "bloom.h"
 #include "test-tool.h"
+#include "bloom.h"
+#include "hex.h"
 #include "commit.h"
+#include "repository.h"
+#include "setup.h"
 
 static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
 
index b18e7603103817b931acf6ab2a8cbbae8538bb8e..475058592d157da39a40ff32231a91f62a5d186a 100644 (file)
@@ -1,6 +1,7 @@
 #include "test-tool.h"
 #include "parse-options.h"
 #include "bundle-uri.h"
+#include "gettext.h"
 #include "strbuf.h"
 #include "string-list.h"
 #include "transport.h"
index 9159a173015cd6efca2f686745cf765e9bdfe58f..e7236392c8132a3720f55148d6c2acbf5de01a41 100644 (file)
@@ -1,9 +1,13 @@
 #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"
 
 static char const * const test_cache_tree_usage[] = {
        N_("test-tool cache-tree <options> (control|prime|update)"),
index dc28890a183f1d123b3356131e90fd588aa5a439..0e5538833a8fb58bf5a8f3910af40ff3bfe8c07f 100644 (file)
@@ -94,7 +94,7 @@ int cmd__chmtime(int argc, const char **argv)
        if (timespec_arg(argv[i], &set_time, &set_eq)) {
                ++i;
        } else {
-               if (get == 0) {
+               if (get == 0 && verbose == 0) {
                        fprintf(stderr, "Not a base-10 integer: %s\n", argv[i] + 1);
                        goto usage;
                }
index 4ba9eb65606d42f70f345a1b18bcd575db31e4cf..ed444ca4c25fbf2c581d5f950609c218b53a341c 100644 (file)
@@ -1,6 +1,6 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "config.h"
+#include "setup.h"
 #include "string-list.h"
 
 /*
@@ -14,6 +14,8 @@
  * get_value_multi -> prints all values for the entered key in increasing order
  *                  of priority
  *
+ * get -> print return value for the entered key
+ *
  * get_int -> print integer value for the entered key or die
  *
  * get_bool -> print bool value for the entered key or die
@@ -30,6 +32,9 @@
  * iterate -> iterate over all values using git_config(), and print some
  *            data for each
  *
+ * git_config_int -> iterate over all values using git_config() and print the
+ *                   integer value for the entered key or die
+ *
  * Examples:
  *
  * To print the value with highest priority for key "foo.bAr Baz.rock":
  *
  */
 
-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++)
@@ -46,15 +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 early_config_cb(const char *var, const char *value, void *vdata)
+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, ctx->kvi);
+               printf("%d\n", parsed);
+       }
+       return 0;
+}
+
+static int early_config_cb(const char *var, const char *value,
+                          const struct config_context *ctx UNUSED,
+                          void *vdata)
 {
        const char *key = vdata;
 
@@ -95,8 +117,7 @@ int cmd__config(int argc, const char **argv)
                        goto exit1;
                }
        } else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) {
-               strptr = git_config_get_value_multi(argv[2]);
-               if (strptr) {
+               if (!git_config_get_value_multi(argv[2], &strptr)) {
                        for (i = 0; i < strptr->nr; i++) {
                                v = strptr->items[i].string;
                                if (!v)
@@ -109,6 +130,26 @@ int cmd__config(int argc, const char **argv)
                        printf("Value not found for \"%s\"\n", argv[2]);
                        goto exit1;
                }
+       } else if (argc == 3 && !strcmp(argv[1], "get")) {
+               int ret;
+
+               if (!(ret = git_config_get(argv[2])))
+                       goto exit0;
+               else if (ret == 1)
+                       printf("Value not found for \"%s\"\n", argv[2]);
+               else if (ret == -CONFIG_INVALID_KEY)
+                       printf("Key \"%s\" is invalid\n", argv[2]);
+               else if (ret == -CONFIG_NO_SECTION_OR_NAME)
+                       printf("Key \"%s\" has no section\n", argv[2]);
+               else
+                       /*
+                        * A normal caller should just check "ret <
+                        * 0", but for our own tests let's BUG() if
+                        * our whitelist of git_config_parse_key()
+                        * return values isn't exhaustive.
+                        */
+                       BUG("Key \"%s\" has unknown return %d", argv[2], ret);
+               goto exit1;
        } else if (argc == 3 && !strcmp(argv[1], "get_int")) {
                if (!git_config_get_int(argv[2], &val)) {
                        printf("%d\n", val);
@@ -141,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
@@ -159,8 +200,7 @@ int cmd__config(int argc, const char **argv)
                                goto exit2;
                        }
                }
-               strptr = git_configset_get_value_multi(&cs, argv[2]);
-               if (strptr) {
+               if (!git_configset_get_value_multi(&cs, argv[2], &strptr)) {
                        for (i = 0; i < strptr->nr; i++) {
                                v = strptr->items[i].string;
                                if (!v)
@@ -176,6 +216,9 @@ int cmd__config(int argc, const char **argv)
        } else if (!strcmp(argv[1], "iterate")) {
                git_config(iterate_cb, NULL);
                goto exit0;
+       } else if (argc == 3 && !strcmp(argv[1], "git_config_int")) {
+               git_config(parse_int_cb, (void *) argv[2]);
+               goto exit0;
        }
 
        die("%s: Please check the syntax and the function name", argv[0]);
index e6c1b1e22bb36da604af3238341f6b7b14753796..597027a96e96c923ff630567a8de2f8c47dad3b2 100644 (file)
@@ -1,5 +1,4 @@
 #include "test-tool.h"
-#include "cache.h"
 
 /*
  * Usage: test-tool crontab <file> -l|<input>
index b21bd672d9ff63d1cf29a9c7a2ad300f0e58c0c0..e5659df40beb01c9eedbad4d65a0e8ff0a81b1b7 100644 (file)
@@ -1,5 +1,4 @@
 #include "test-tool.h"
-#include "cache.h"
 
 static int rc;
 
@@ -28,6 +27,8 @@ static int is_in(const char *s, int ch)
                if (is_in(s, i) != t(i))        \
                        report_error(#t, i);    \
        }                                       \
+       if (t(EOF))                             \
+               report_error(#t, EOF);          \
 }
 
 #define DIGIT "0123456789"
@@ -48,7 +49,7 @@ static int is_in(const char *s, int ch)
        "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
        "\x7f"
 
-int cmd__ctype(int argc, const char **argv)
+int cmd__ctype(int argc UNUSED, const char **argv UNUSED)
 {
        TEST_CLASS(isdigit, DIGIT);
        TEST_CLASS(isspace, " \n\r\t");
index 45951b1df87c7bf90a25cc1497344681ae42a161..0683d46574fa41e6b4186e8ec49d06ce65d93256 100644 (file)
@@ -1,6 +1,6 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "date.h"
+#include "trace.h"
 
 static const char *usage_msg = "\n"
 "  test-tool date relative [time_t]...\n"
@@ -81,7 +81,7 @@ static void parse_approxidate(const char **argv)
 {
        for (; *argv; argv++) {
                timestamp_t t;
-               t = approxidate_relative(*argv);
+               t = approxidate(*argv);
                printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601)));
        }
 }
@@ -90,7 +90,7 @@ static void parse_approx_timestamp(const char **argv)
 {
        for (; *argv; argv++) {
                timestamp_t t;
-               t = approxidate_relative(*argv);
+               t = approxidate(*argv);
                printf("%s -> %"PRItime"\n", *argv, t);
        }
 }
@@ -104,7 +104,7 @@ static void getnanos(const char **argv)
        printf("%lf\n", seconds);
 }
 
-int cmd__date(int argc, const char **argv)
+int cmd__date(int argc UNUSED, const char **argv)
 {
        const char *x;
 
index b15481ea596dcdd2337a4dd9d99761ecb5514ea4..6bc787a4743be08fcd1b977ced58273c3bf274d0 100644 (file)
@@ -11,7 +11,6 @@
 #include "test-tool.h"
 #include "git-compat-util.h"
 #include "delta.h"
-#include "cache.h"
 
 static const char usage_str[] =
        "test-tool delta (-d|-p) <from_file> <data_file> <out_file>";
index e37396dd9c2c2fe01b9bf2acc8d6a2c6456869fc..73e551cfc222695c31bfc6897d12dc025c87b439 100644 (file)
@@ -155,7 +155,7 @@ static int cmd_dropcaches(void)
 
 #endif
 
-int cmd__drop_caches(int argc, const char **argv)
+int cmd__drop_caches(int argc UNUSED, const char **argv UNUSED)
 {
        cmd_sync();
        return cmd_dropcaches();
index 454f17b1a0c1cceadffd6293db43790dcf42972a..c38f546e4f096fbd3e9b6cb13ab96bb800f56504 100644 (file)
@@ -1,9 +1,12 @@
 #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"
 
 static void dump_one(struct cache_tree *it, const char *pfx, const char *x)
 {
@@ -56,7 +59,7 @@ static int dump_cache_tree(struct cache_tree *it,
        return errs;
 }
 
-int cmd__dump_cache_tree(int ac, const char **av)
+int cmd__dump_cache_tree(int ac UNUSED, const char **av UNUSED)
 {
        struct index_state istate;
        struct cache_tree *another = cache_tree();
index 975f0ac8905125f01ce37be5b7bc862cf058fbcf..4f215fea025290f868defcae8bdca5aeefc627ba 100644 (file)
@@ -1,7 +1,9 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
 
-int cmd__dump_fsmonitor(int ac, const char **av)
+int cmd__dump_fsmonitor(int ac UNUSED, const char **av UNUSED)
 {
        struct index_state *istate = the_repository->index;
        int i;
index 0ea97b8407296a3615ab786e9458ff9bbf638000..f29d18ef9490b7a0dd8fd689082a68b4cd5332b0 100644 (file)
@@ -1,15 +1,18 @@
 #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);
 }
 
-int cmd__dump_split_index(int ac, const char **av)
+int cmd__dump_split_index(int ac UNUSED, const char **av)
 {
        struct split_index *si;
        int i;
index 6d53683f13b04c2c89680408f3e348cf97043ffd..b4af9712fe5f2cfb815e22dc41a588890faecea5 100644 (file)
@@ -1,7 +1,10 @@
 #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"
 
 static int compare_untracked(const void *a_, const void *b_)
 {
@@ -40,7 +43,7 @@ static void dump(struct untracked_cache_dir *ucd, struct strbuf *base)
        strbuf_setlen(base, len);
 }
 
-int cmd__dump_untracked_cache(int ac, const char **av)
+int cmd__dump_untracked_cache(int ac UNUSED, const char **av UNUSED)
 {
        struct untracked_cache *uc;
        struct strbuf base = STRBUF_INIT;
index b9d1200eb988e19f3f0a2c0aeed941a6eb44b9bb..2ed910adaa3da3b5db771679ccb1eefb0a8da2f5 100644 (file)
@@ -1,9 +1,10 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "git-compat-util.h"
 #include "object.h"
 #include "decorate.h"
+#include "repository.h"
 
-int cmd__example_decorate(int argc, const char **argv)
+int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
 {
        struct decoration n;
        struct object_id one_oid = { {1} };
index efc82dd80c5b5711ecb4947b3c082433845e1e50..cac20a72b3fcb52c5ccb66cbbb1679ecb8f39f97 100644 (file)
 
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.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"
+#include "setup.h"
 #include "strvec.h"
 #include "tree.h"
 
 static const char *short_commit_name(struct commit *commit)
 {
-       return find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV);
+       return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+                                      DEFAULT_ABBREV);
 }
 
 static struct commit *peel_committish(const char *name)
@@ -33,10 +40,11 @@ static struct commit *peel_committish(const char *name)
        struct object *obj;
        struct object_id oid;
 
-       if (get_oid(name, &oid))
+       if (repo_get_oid(the_repository, name, &oid))
                return NULL;
        obj = parse_object(the_repository, &oid);
-       return (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
+       return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
+                                                 OBJ_COMMIT);
 }
 
 static char *get_author(const char *message)
@@ -63,7 +71,8 @@ static struct commit *create_commit(struct tree *tree,
        struct commit_extra_header *extra;
        struct strbuf msg = STRBUF_INIT;
        const char *out_enc = get_commit_output_encoding();
-       const char *message = logmsg_reencode(based_on, NULL, out_enc);
+       const char *message = repo_logmsg_reencode(the_repository, based_on,
+                                                  NULL, out_enc);
        const char *orig_message = NULL;
        const char *exclude_gpgsig[] = { "gpgsig", NULL };
 
@@ -119,7 +128,7 @@ int cmd__fast_rebase(int argc, const char **argv)
        strbuf_addf(&branch_name, "refs/heads/%s", argv[4]);
 
        /* Sanity check */
-       if (get_oid("HEAD", &head))
+       if (repo_get_oid(the_repository, "HEAD", &head))
                die(_("Cannot read HEAD"));
        assert(oideq(&onto->object.oid, &head));
 
@@ -154,7 +163,7 @@ int cmd__fast_rebase(int argc, const char **argv)
        memset(&result, 0, sizeof(result));
        merge_opt.show_rename_progress = 1;
        merge_opt.branch1 = "HEAD";
-       head_tree = get_commit_tree(onto);
+       head_tree = repo_get_commit_tree(the_repository, onto);
        result.tree = head_tree;
        last_commit = onto;
        while ((commit = get_revision(&revs))) {
@@ -165,8 +174,8 @@ int cmd__fast_rebase(int argc, const char **argv)
                assert(commit->parents && !commit->parents->next);
                base = commit->parents->item;
 
-               next_tree = get_commit_tree(commit);
-               base_tree = get_commit_tree(base);
+               next_tree = repo_get_commit_tree(the_repository, commit);
+               base_tree = repo_get_commit_tree(the_repository, base);
 
                merge_opt.branch2 = short_commit_name(commit);
                merge_opt.ancestor = xstrfmt("parent of %s", merge_opt.branch2);
index 54a4856c48c55af0af4e3ffe7cc3a62dce993842..8280984d08fe84b23722948709e83252e5d40895 100644 (file)
@@ -4,14 +4,16 @@
  */
 
 #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"
 
 #ifndef HAVE_FSMONITOR_DAEMON_BACKEND
-int cmd__fsmonitor_client(int argc, const char **argv)
+int cmd__fsmonitor_client(int argc UNUSED, const char **argv UNUSED)
 {
        die("fsmonitor--daemon not available on this platform");
 }
index f40d9ad0c2ddd293f2b1a1e7e142885ede078ae6..b235da594f749b1a6b680d0b674c5bb822b1b978 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
 
 #define NUM_SECONDS 3
 
index 5860dab0ffac976bc3e6d0ef2da2153566477018..45d829c908fec95ded535ebcfe502c3bb4aa5441 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
 
 int cmd_hash_impl(int ac, const char **av, int algo)
 {
index 36ff07bd4beaefabe5f42d119b0eac26cf3ae8d9..0eb0b3d49cecc57ae08a4760065eb7b530a5f191 100644 (file)
@@ -2,6 +2,7 @@
 #include "git-compat-util.h"
 #include "hashmap.h"
 #include "strbuf.h"
+#include "string-list.h"
 
 struct test_entry
 {
@@ -150,6 +151,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
  */
 int cmd__hashmap(int argc, const char **argv)
 {
+       struct string_list parts = STRING_LIST_INIT_NODUP;
        struct strbuf line = STRBUF_INIT;
        int icase;
        struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
@@ -159,21 +161,26 @@ int cmd__hashmap(int argc, const char **argv)
 
        /* process commands from stdin */
        while (strbuf_getline(&line, stdin) != EOF) {
-               char *cmd, *p1 = NULL, *p2 = NULL;
+               char *cmd, *p1, *p2;
                unsigned int hash = 0;
                struct test_entry *entry;
 
                /* break line into command and up to two parameters */
-               cmd = strtok(line.buf, DELIM);
+               string_list_setlen(&parts, 0);
+               string_list_split_in_place(&parts, line.buf, DELIM, 2);
+               string_list_remove_empty_items(&parts, 0);
+
                /* ignore empty lines */
-               if (!cmd || *cmd == '#')
+               if (!parts.nr)
+                       continue;
+               if (!*parts.items[0].string || *parts.items[0].string == '#')
                        continue;
 
-               p1 = strtok(NULL, DELIM);
-               if (p1) {
+               cmd = parts.items[0].string;
+               p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
+               p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
+               if (p1)
                        hash = icase ? strihash(p1) : strhash(p1);
-                       p2 = strtok(NULL, DELIM);
-               }
 
                if (!strcmp("add", cmd) && p1 && p2) {
 
@@ -260,6 +267,7 @@ int cmd__hashmap(int argc, const char **argv)
                }
        }
 
+       string_list_clear(&parts, 0);
        strbuf_release(&line);
        hashmap_clear_and_free(&map, struct test_entry, ent);
        return 0;
index 811e89c1bcb0289e63588c2dbb801f34982cbc56..05f55eca21afb8792d60498fd9e1fc88d5499a72 100644 (file)
@@ -4,7 +4,7 @@
 /*
  * Read stdin and print a hexdump to stdout.
  */
-int cmd__hexdump(int argc, const char **argv)
+int cmd__hexdump(int argc UNUSED, const char **argv UNUSED)
 {
        char buf[1024];
        ssize_t i, len;
index fcd10968cc10bdab8db146b8ba65080431e5ed24..f3c2dbe0a2ca512beff2821715d65bd625b3126a 100644 (file)
@@ -1,7 +1,7 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
 
-int cmd__index_version(int argc, const char **argv)
+int cmd__index_version(int argc UNUSED, const char **argv UNUSED)
 {
        struct cache_header hdr;
        int version;
index 8c3edacc0007df7ddb52f2f65d00e44b95edeb5a..afe393f5974131b390f2eca932960cbd962f0b6d 100644 (file)
@@ -1,6 +1,6 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "json-writer.h"
+#include "string-list.h"
 
 static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}";
 static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}";
@@ -395,35 +395,41 @@ static int unit_tests(void)
        return 0;
 }
 
-static void get_s(int line_nr, char **s_in)
+struct line {
+       struct string_list *parts;
+       size_t consumed_nr;
+       int nr;
+};
+
+static void get_s(struct line *line, char **s_in)
 {
-       *s_in = strtok(NULL, " ");
-       if (!*s_in)
-               die("line[%d]: expected: <s>", line_nr);
+       if (line->consumed_nr > line->parts->nr)
+               die("line[%d]: expected: <s>", line->nr);
+       *s_in = line->parts->items[line->consumed_nr++].string;
 }
 
-static void get_i(int line_nr, intmax_t *s_in)
+static void get_i(struct line *line, intmax_t *s_in)
 {
        char *s;
        char *endptr;
 
-       get_s(line_nr, &s);
+       get_s(line, &s);
 
        *s_in = strtol(s, &endptr, 10);
        if (*endptr || errno == ERANGE)
-               die("line[%d]: invalid integer value", line_nr);
+               die("line[%d]: invalid integer value", line->nr);
 }
 
-static void get_d(int line_nr, double *s_in)
+static void get_d(struct line *line, double *s_in)
 {
        char *s;
        char *endptr;
 
-       get_s(line_nr, &s);
+       get_s(line, &s);
 
        *s_in = strtod(s, &endptr);
        if (*endptr || errno == ERANGE)
-               die("line[%d]: invalid float value", line_nr);
+               die("line[%d]: invalid float value", line->nr);
 }
 
 static int pretty;
@@ -454,6 +460,7 @@ static char *get_trimmed_line(char *buf, int buf_size)
 
 static int scripted(void)
 {
+       struct string_list parts = STRING_LIST_INIT_NODUP;
        struct json_writer jw = JSON_WRITER_INIT;
        char buf[MAX_LINE_LENGTH];
        char *line;
@@ -471,66 +478,77 @@ static int scripted(void)
                die("expected first line to be 'object' or 'array'");
 
        while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) {
+               struct line state = { 0 };
                char *verb;
                char *key;
                char *s_value;
                intmax_t i_value;
                double d_value;
 
-               line_nr++;
+               state.parts = &parts;
+               state.nr = ++line_nr;
+
+               /* break line into command and zero or more tokens */
+               string_list_setlen(&parts, 0);
+               string_list_split_in_place(&parts, line, " ", -1);
+               string_list_remove_empty_items(&parts, 0);
+
+               /* ignore empty lines */
+               if (!parts.nr || !*parts.items[0].string)
+                       continue;
 
-               verb = strtok(line, " ");
+               verb = parts.items[state.consumed_nr++].string;
 
                if (!strcmp(verb, "end")) {
                        jw_end(&jw);
                }
                else if (!strcmp(verb, "object-string")) {
-                       get_s(line_nr, &key);
-                       get_s(line_nr, &s_value);
+                       get_s(&state, &key);
+                       get_s(&state, &s_value);
                        jw_object_string(&jw, key, s_value);
                }
                else if (!strcmp(verb, "object-int")) {
-                       get_s(line_nr, &key);
-                       get_i(line_nr, &i_value);
+                       get_s(&state, &key);
+                       get_i(&state, &i_value);
                        jw_object_intmax(&jw, key, i_value);
                }
                else if (!strcmp(verb, "object-double")) {
-                       get_s(line_nr, &key);
-                       get_i(line_nr, &i_value);
-                       get_d(line_nr, &d_value);
+                       get_s(&state, &key);
+                       get_i(&state, &i_value);
+                       get_d(&state, &d_value);
                        jw_object_double(&jw, key, i_value, d_value);
                }
                else if (!strcmp(verb, "object-true")) {
-                       get_s(line_nr, &key);
+                       get_s(&state, &key);
                        jw_object_true(&jw, key);
                }
                else if (!strcmp(verb, "object-false")) {
-                       get_s(line_nr, &key);
+                       get_s(&state, &key);
                        jw_object_false(&jw, key);
                }
                else if (!strcmp(verb, "object-null")) {
-                       get_s(line_nr, &key);
+                       get_s(&state, &key);
                        jw_object_null(&jw, key);
                }
                else if (!strcmp(verb, "object-object")) {
-                       get_s(line_nr, &key);
+                       get_s(&state, &key);
                        jw_object_inline_begin_object(&jw, key);
                }
                else if (!strcmp(verb, "object-array")) {
-                       get_s(line_nr, &key);
+                       get_s(&state, &key);
                        jw_object_inline_begin_array(&jw, key);
                }
                else if (!strcmp(verb, "array-string")) {
-                       get_s(line_nr, &s_value);
+                       get_s(&state, &s_value);
                        jw_array_string(&jw, s_value);
                }
                else if (!strcmp(verb, "array-int")) {
-                       get_i(line_nr, &i_value);
+                       get_i(&state, &i_value);
                        jw_array_intmax(&jw, i_value);
                }
                else if (!strcmp(verb, "array-double")) {
-                       get_i(line_nr, &i_value);
-                       get_d(line_nr, &d_value);
+                       get_i(&state, &i_value);
+                       get_d(&state, &d_value);
                        jw_array_double(&jw, i_value, d_value);
                }
                else if (!strcmp(verb, "array-true"))
@@ -553,6 +571,7 @@ static int scripted(void)
        printf("%s\n", jw.json.buf);
 
        jw_release(&jw);
+       string_list_clear(&parts, 0);
        return 0;
 }
 
index ab86c14c8ba56b513ea302842ad9fbf638507404..187a115d5743f39f7b93e0bf128ead62262a12bb 100644 (file)
@@ -1,7 +1,12 @@
 #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"
 
 static int single;
 static int multi;
index 4079fdee06776c8179fbc15283141f3890ff013e..d0db5ff26f0772373b5ccba7ad0aa89df01548ff 100644 (file)
@@ -1,17 +1,21 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
+#include "match-trees.h"
+#include "object-name.h"
+#include "repository.h"
+#include "setup.h"
 #include "tree.h"
 
-int cmd__match_trees(int ac, const char **av)
+int cmd__match_trees(int ac UNUSED, const char **av)
 {
        struct object_id hash1, hash2, shifted;
        struct tree *one, *two;
 
        setup_git_directory();
 
-       if (get_oid(av[1], &hash1))
+       if (repo_get_oid(the_repository, av[1], &hash1))
                die("cannot parse %s as an object name", av[1]);
-       if (get_oid(av[2], &hash2))
+       if (repo_get_oid(the_repository, av[2], &hash2))
                die("cannot parse %s as an object name", av[2]);
        one = parse_tree_indirect(&hash1);
        if (!one)
index 335e5bb3a9008c8ce1cb31198bd54808c70566dc..42ccc8705167b07266a5c3902fba7cb7a8081c64 100644 (file)
@@ -1,6 +1,7 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "mem-pool.h"
 #include "mergesort.h"
+#include "strbuf.h"
 
 static uint32_t minstd_rand(uint32_t *state)
 {
index d1324d086a24c0575e6beadaeef2ce1e8b6a80f0..aafe398ef07e538ef774fedc72cd27189391f2fb 100644 (file)
@@ -1,14 +1,16 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
 #include "oid-array.h"
+#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;
 }
 
-int cmd__oid_array(int argc, const char **argv)
+int cmd__oid_array(int argc UNUSED, const char **argv UNUSED)
 {
        struct oid_array array = OID_ARRAY_INIT;
        struct strbuf line = STRBUF_INIT;
index 0acf99931ee176982d61078dc0e2d882377c05fd..bd30244a54cc88370ab27da5d25108b78c296f85 100644 (file)
@@ -1,7 +1,11 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
+#include "object-name.h"
 #include "oidmap.h"
+#include "repository.h"
+#include "setup.h"
 #include "strbuf.h"
+#include "string-list.h"
 
 /* key is an oid and value is a name (could be a refname for example) */
 struct test_entry {
@@ -21,8 +25,9 @@ struct test_entry {
  * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n...
  *
  */
-int cmd__oidmap(int argc, const char **argv)
+int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
 {
+       struct string_list parts = STRING_LIST_INIT_NODUP;
        struct strbuf line = STRBUF_INIT;
        struct oidmap map = OIDMAP_INIT;
 
@@ -33,23 +38,28 @@ int cmd__oidmap(int argc, const char **argv)
 
        /* process commands from stdin */
        while (strbuf_getline(&line, stdin) != EOF) {
-               char *cmd, *p1 = NULL, *p2 = NULL;
+               char *cmd, *p1, *p2;
                struct test_entry *entry;
                struct object_id oid;
 
                /* break line into command and up to two parameters */
-               cmd = strtok(line.buf, DELIM);
+               string_list_setlen(&parts, 0);
+               string_list_split_in_place(&parts, line.buf, DELIM, 2);
+               string_list_remove_empty_items(&parts, 0);
+
                /* ignore empty lines */
-               if (!cmd || *cmd == '#')
+               if (!parts.nr)
+                       continue;
+               if (!*parts.items[0].string || *parts.items[0].string == '#')
                        continue;
 
-               p1 = strtok(NULL, DELIM);
-               if (p1)
-                       p2 = strtok(NULL, DELIM);
+               cmd = parts.items[0].string;
+               p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
+               p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
 
                if (!strcmp("put", cmd) && p1 && p2) {
 
-                       if (get_oid(p1, &oid)) {
+                       if (repo_get_oid(the_repository, p1, &oid)) {
                                printf("Unknown oid: %s\n", p1);
                                continue;
                        }
@@ -67,7 +77,7 @@ int cmd__oidmap(int argc, const char **argv)
 
                } else if (!strcmp("get", cmd) && p1) {
 
-                       if (get_oid(p1, &oid)) {
+                       if (repo_get_oid(the_repository, p1, &oid)) {
                                printf("Unknown oid: %s\n", p1);
                                continue;
                        }
@@ -80,7 +90,7 @@ int cmd__oidmap(int argc, const char **argv)
 
                } else if (!strcmp("remove", cmd) && p1) {
 
-                       if (get_oid(p1, &oid)) {
+                       if (repo_get_oid(the_repository, p1, &oid)) {
                                printf("Unknown oid: %s\n", p1);
                                continue;
                        }
@@ -106,6 +116,7 @@ int cmd__oidmap(int argc, const char **argv)
                }
        }
 
+       string_list_clear(&parts, 0);
        strbuf_release(&line);
        oidmap_free(&map, 1);
        return 0;
index d48a409f4e4fb377a7cbc4684fa05737ea32f2c1..c7a1d4c6420118e06923b2aa0f28cc6f8e983edc 100644 (file)
@@ -1,14 +1,16 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
 #include "oidtree.h"
+#include "setup.h"
+#include "strbuf.h"
 
-static enum cb_next print_oid(const struct object_id *oid, void *data)
+static enum cb_next print_oid(const struct object_id *oid, void *data UNUSED)
 {
        puts(oid_to_hex(oid));
        return CB_CONTINUE;
 }
 
-int cmd__oidtree(int argc, const char **argv)
+int cmd__oidtree(int argc UNUSED, const char **argv UNUSED)
 {
        struct oidtree ot;
        struct strbuf line = STRBUF_INIT;
index 8cb0d53840f3dc60d583fa1b72f95572d2148d11..47dc21171125cde0bd67877517b53a26e8a289eb 100644 (file)
@@ -2,7 +2,7 @@
 #include "git-compat-util.h"
 #include "thread-utils.h"
 
-int cmd__online_cpus(int argc, const char **argv)
+int cmd__online_cpus(int argc UNUSED, const char **argv UNUSED)
 {
        printf("%d\n", online_cpus());
        return 0;
index f7b79daf4c03843c5003100b63666f8dbdbfd1d5..67a964ef9041a061497c0b10698413d360f561e1 100644 (file)
@@ -1,9 +1,10 @@
-#include "git-compat-util.h"
 #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"
 
 static void dump_mtimes(struct packed_git *p)
 {
index 506835521a463aebd1a06259cf96e05d71e3833b..a4f6e24b0c6e1bf6557803921b5e9b21853791a3 100644 (file)
@@ -1,6 +1,6 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "parse-options.h"
+#include "strbuf.h"
 #include "string-list.h"
 #include "trace2.h"
 
@@ -133,6 +133,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",
@@ -263,14 +265,14 @@ int cmd__parse_options_flags(int argc, const char **argv)
        return parse_options_flags__cmd(argc, argv, test_flags);
 }
 
-static int subcmd_one(int argc, const char **argv, const char *prefix)
+static int subcmd_one(int argc, const char **argv, const char *prefix UNUSED)
 {
        printf("fn: subcmd_one\n");
        print_args(argc, argv);
        return 0;
 }
 
-static int subcmd_two(int argc, const char **argv, const char *prefix)
+static int subcmd_two(int argc, const char **argv, const char *prefix UNUSED)
 {
        printf("fn: subcmd_two\n");
        print_args(argc, argv);
index b3e08cef4b3f86ba95509f1d66345f7ca6016ea3..89ecefd1cdbec1da7c2cd43dbceebeb05ac61708 100644 (file)
@@ -1,12 +1,11 @@
 #include "test-tool.h"
 #include "parse-options.h"
 #include "pathspec.h"
-#include "gettext.h"
 
 int cmd__parse_pathspec_file(int argc, const char **argv)
 {
        struct pathspec pathspec;
-       const char *pathspec_from_file = NULL;
+       char *pathspec_from_file = NULL;
        int pathspec_file_nul = 0, i;
 
        static const char *const usage[] = {
@@ -29,5 +28,6 @@ int cmd__parse_pathspec_file(int argc, const char **argv)
                printf("%s\n", pathspec.items[i].original);
 
        clear_pathspec(&pathspec);
+       free(pathspec_from_file);
        return 0;
 }
index 3f102cfddd3f4b6fe85391a8a2fc3a11b9b509c7..910a12861442264ca951a1a2ef27e6fb20eb7985 100644 (file)
@@ -1,7 +1,8 @@
-#include "cache.h"
 #include "test-tool.h"
+#include "hex.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "setup.h"
 
 /*
  * Prints the size of the object corresponding to the given hash in a specific
index f69709d674fe18a14e0357e4a729a318512c450e..70396fa38454e86d661b9a4857e3ef463ee40f63 100644 (file)
@@ -1,6 +1,11 @@
 #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"
 #include "utf8.h"
 
 /*
index 5258fdddba0eb36829c04216fbb71b1a196810d0..5d0b2a2e10fa66e16dd954f97ba7561b106fce50 100644 (file)
@@ -1,5 +1,4 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "grep.h"
 
 int cmd__pcre2_config(int argc, const char **argv)
index c5e052e537805075682f16204f1ab16991a8e0fe..f4d134a145214f3964e781db949c05cf51f32fc5 100644 (file)
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "test-tool.h"
 #include "pkt-line.h"
+#include "write-or-die.h"
 
 static void pack_line(const char *line)
 {
index 133b5e6f4ae5fdbd90f6594223df60f918a036f4..f0bf255f5f0581d91b5f189dbf06f9b3cf910cc9 100644 (file)
@@ -1,8 +1,7 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "prio-queue.h"
 
-static int intcmp(const void *va, const void *vb, void *data)
+static int intcmp(const void *va, const void *vb, void *data UNUSED)
 {
        const int *a = va, *b = vb;
        return *a - *b;
@@ -17,7 +16,7 @@ static void show(int *v)
        free(v);
 }
 
-int cmd__prio_queue(int argc, const char **argv)
+int cmd__prio_queue(int argc UNUSED, const char **argv)
 {
        struct prio_queue pq = { intcmp };
 
index a4b305f4947fd21da757807a4e85c1c62987867f..f30022d2225b0a81cb026a9ccc24366ebdb9d2b4 100644 (file)
@@ -1,9 +1,10 @@
-#include "cache.h"
+#include "test-tool.h"
 #include "connect.h"
+#include "hex.h"
 #include "parse-options.h"
 #include "pkt-line.h"
+#include "setup.h"
 #include "sigchain.h"
-#include "test-tool.h"
 
 static const char *proc_receive_usage[] = {
        "test-tool proc-receive [<options>]",
index 6cc9735b60127b2f5bab7d1728dc013a27b7adf4..66acb6a06c99b062952c0c34e6f527ecb06bc222 100644 (file)
@@ -19,7 +19,6 @@
  */
 #define GIT_TEST_PROGRESS_ONLY
 #include "test-tool.h"
-#include "gettext.h"
 #include "parse-options.h"
 #include "progress.h"
 #include "strbuf.h"
index 2f65c7f6a55bc146ea69ea9ef85d45a1f6172ac3..3e173399a00f5296a70aa293107dfb4db94b1633 100644 (file)
@@ -1,10 +1,13 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "commit.h"
 #include "commit-reach.h"
 #include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
 #include "parse-options.h"
 #include "ref-filter.h"
+#include "setup.h"
 #include "string-list.h"
 #include "tag.h"
 
@@ -57,7 +60,7 @@ int cmd__reach(int ac, const char **av)
                if (buf.len < 3)
                        continue;
 
-               if (get_oid_committish(buf.buf + 2, &oid))
+               if (repo_get_oid_committish(the_repository, buf.buf + 2, &oid))
                        die("failed to resolve %s", buf.buf + 2);
 
                orig = parse_object(r, &oid);
@@ -106,13 +109,17 @@ int cmd__reach(int ac, const char **av)
        if (!strcmp(av[1], "ref_newer"))
                printf("%s(A,B):%d\n", av[1], ref_newer(&oid_A, &oid_B));
        else if (!strcmp(av[1], "in_merge_bases"))
-               printf("%s(A,B):%d\n", av[1], in_merge_bases(A, B));
+               printf("%s(A,B):%d\n", av[1],
+                      repo_in_merge_bases(the_repository, A, B));
        else if (!strcmp(av[1], "in_merge_bases_many"))
-               printf("%s(A,X):%d\n", av[1], in_merge_bases_many(A, X_nr, X_array));
+               printf("%s(A,X):%d\n", av[1],
+                      repo_in_merge_bases_many(the_repository, A, X_nr, X_array));
        else if (!strcmp(av[1], "is_descendant_of"))
                printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
        else if (!strcmp(av[1], "get_merge_bases_many")) {
-               struct commit_list *list = get_merge_bases_many(A, X_nr, X_array);
+               struct commit_list *list = repo_get_merge_bases_many(the_repository,
+                                                                    A, X_nr,
+                                                                    X_array);
                printf("%s(A,X):\n", av[1]);
                print_sorted_commit_ids(list);
        } else if (!strcmp(av[1], "reduce_heads")) {
@@ -131,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 23e9e27109faa2acac0bd2804e1143efc7c8971b..1acd3623465283e4751a75bce0cbb8bf1926bcd7 100644 (file)
@@ -1,7 +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"
 
 int cmd__read_cache(int argc, const char **argv)
 {
index 98b73bb8f25aabea7384cde0fb639cff16cf631e..8c7a83f578f41c3d90bcb17628bd5307e5927636 100644 (file)
@@ -1,11 +1,11 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "commit-graph.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "bloom.h"
+#include "setup.h"
 
-int cmd__read_graph(int argc, const char **argv)
+int cmd__read_graph(int argc UNUSED, const char **argv UNUSED)
 {
        struct commit_graph *graph = NULL;
        struct object_directory *odb;
index 27072ba94d76005b6f49e04f60f2e697efd0e073..e9a444ddba55b49c9c47ceb3b27a31d3e022a8dc 100644 (file)
@@ -1,9 +1,11 @@
 #include "test-tool.h"
-#include "cache.h"
+#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"
 
 static int read_midx_file(const char *object_dir, int show_objects)
 {
index ae8a5648daf5c1385afe43f327bf9a5a3d98e1f1..48552e6a9e0049365185499c02d9b1c7d1069d0c 100644 (file)
@@ -1,9 +1,13 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hex.h"
 #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;
@@ -115,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)
@@ -174,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();
@@ -200,7 +221,8 @@ static int cmd_verify_ref(struct ref_store *refs, const char **argv)
        return ret;
 }
 
-static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)
+static int cmd_for_each_reflog(struct ref_store *refs,
+                              const char **argv UNUSED)
 {
        return refs_for_each_reflog(refs, each_ref, NULL);
 }
@@ -255,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");
@@ -305,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 },
@@ -313,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
         */
@@ -322,7 +339,7 @@ static struct command commands[] = {
        { NULL, NULL }
 };
 
-int cmd__ref_store(int argc, const char **argv)
+int cmd__ref_store(int argc UNUSED, const char **argv)
 {
        struct ref_store *refs;
        const char *func;
index 1f0a28cbb64de427ff8d8c542e0b1166250093e2..00237ef0d9e08fb9747010891b64d1d5ca421a29 100644 (file)
@@ -1,3 +1,4 @@
+#include "reftable/system.h"
 #include "reftable/reftable-tests.h"
 #include "test-tool.h"
 
index 56f0e3c1bef293dd505e28af4b48dfce11490b3c..4cd8a952e5c6f55fbb3cfdbffe8c3be07bf008d7 100644 (file)
@@ -1,11 +1,13 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "commit-graph.h"
 #include "commit.h"
 #include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-store-ll.h"
 #include "object.h"
 #include "repository.h"
+#include "setup.h"
 #include "tree.h"
 
 static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
index 4a45d5bac2af5678eda5ad8b49c7747a3973878e..f346951bc28c99e4791d841fac0d873a128cc973 100644 (file)
@@ -9,17 +9,19 @@
  */
 
 #include "test-tool.h"
-#include "cache.h"
 #include "commit.h"
 #include "diff.h"
+#include "repository.h"
 #include "revision.h"
+#include "setup.h"
 
 static void print_commit(struct commit *commit)
 {
        struct strbuf sb = STRBUF_INIT;
        struct pretty_print_context ctx = {0};
        ctx.date_mode.type = DATE_NORMAL;
-       format_commit_message(commit, " %m %s", &sb, &ctx);
+       repo_format_commit_message(the_repository, commit, " %m %s", &sb,
+                                  &ctx);
        printf("%s\n", sb.buf);
        strbuf_release(&sb);
 }
index 3ecb830f4a8cd196f20ff0c371108c8f5579f3cd..c0ed8722c8779b7617382959ff92f2e0a2ea8db6 100644 (file)
@@ -9,8 +9,6 @@
  */
 
 #include "test-tool.h"
-#include "git-compat-util.h"
-#include "cache.h"
 #include "run-command.h"
 #include "strvec.h"
 #include "strbuf.h"
 #include "string-list.h"
 #include "thread-utils.h"
 #include "wildmatch.h"
-#include "gettext.h"
 
 static int number_callbacks;
 static int parallel_next(struct child_process *cp,
                         struct strbuf *err,
                         void *cb,
-                        void **task_cb)
+                        void **task_cb UNUSED)
 {
        struct child_process *d = cb;
        if (number_callbacks >= 4)
@@ -40,10 +37,10 @@ static int parallel_next(struct child_process *cp,
        return 1;
 }
 
-static int no_job(struct child_process *cp,
+static int no_job(struct child_process *cp UNUSED,
                  struct strbuf *err,
-                 void *cb,
-                 void **task_cb)
+                 void *cb UNUSED,
+                 void **task_cb UNUSED)
 {
        if (err)
                strbuf_addstr(err, "no further jobs available\n");
@@ -52,10 +49,10 @@ static int no_job(struct child_process *cp,
        return 0;
 }
 
-static int task_finished(int result,
+static int task_finished(int result UNUSED,
                         struct strbuf *err,
-                        void *pp_cb,
-                        void *pp_task_cb)
+                        void *pp_cb UNUSED,
+                        void *pp_task_cb UNUSED)
 {
        if (err)
                strbuf_addstr(err, "asking for a quick stop\n");
index a26107ed70ac023da79a573bf0d87cdad95016d0..0a816a96e28b6c43a0b4927418c97bb11ba5298c 100644 (file)
@@ -1,11 +1,13 @@
 #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"
 #include "cache-tree.h"
 
-int cmd__scrap_cache_tree(int ac, const char **av)
+int cmd__scrap_cache_tree(int ac UNUSED, const char **av UNUSED)
 {
        struct lock_file index_lock = LOCK_INIT;
 
index 824e5c0a95819f8d11393a74da4b231728bb0615..054cbcf5d83946b225774dc9da6b0ec1d112e79d 100644 (file)
@@ -1,7 +1,8 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "gettext.h"
 #include "parse-options.h"
 #include "serve.h"
+#include "setup.h"
 
 static char const * const serve_usage[] = {
        N_("test-tool serve-v2 [<options>]"),
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 d013bccddaebd9c7fb0eb4b4c4e1be0643f82260..2d5ecf738317e7a8a3897bc5ff5a7cc0e51de2da 100644 (file)
@@ -1,5 +1,4 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "sigchain.h"
 
 #define X(f) \
@@ -14,7 +13,7 @@ X(two)
 X(three)
 #undef X
 
-int cmd__sigchain(int argc, const char **argv)
+int cmd__sigchain(int argc UNUSED, const char **argv UNUSED)
 {
        sigchain_push(SIGTERM, one);
        sigchain_push(SIGTERM, two);
index 28365ff85b69bbda4ca47b5284b2cbd7bebea9e9..3d1436da59872fcfe7551a5586c7720893221ddb 100644 (file)
@@ -3,13 +3,14 @@
  */
 
 #include "test-tool.h"
-#include "cache.h"
+#include "gettext.h"
 #include "strbuf.h"
 #include "simple-ipc.h"
 #include "parse-options.h"
 #include "thread-utils.h"
 #include "strvec.h"
 #include "run-command.h"
+#include "trace2.h"
 
 #ifndef SUPPORTS_SIMPLE_IPC
 int cmd__simple_ipc(int argc, const char **argv)
index 44e4a6d143e24cbd05b5d94404a5f5d4e732c880..d8473cf2fcfeb61bdbced865455dd2e3a35b71bb 100644 (file)
@@ -1,7 +1,7 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
 
-int cmd__strcmp_offset(int argc, const char **argv)
+int cmd__strcmp_offset(int argc UNUSED, const char **argv)
 {
        int result;
        size_t offset;
index 2123dda85bf10033dcbf0d801028b3705e73a507..e2aad611d1c8bbc110c877c7d7555c046b82e7db 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "strbuf.h"
 #include "string-list.h"
 
 /*
@@ -62,7 +62,7 @@ int cmd__string_list(int argc, const char **argv)
                struct string_list list = STRING_LIST_INIT_NODUP;
                int i;
                char *s = xstrdup(argv[2]);
-               int delim = *argv[3];
+               const char *delim = argv[3];
                int maxsplit = atoi(argv[4]);
 
                i = string_list_split_in_place(&list, s, delim, maxsplit);
@@ -111,7 +111,7 @@ int cmd__string_list(int argc, const char **argv)
                 */
                if (sb.len && sb.buf[sb.len - 1] == '\n')
                        strbuf_setlen(&sb, sb.len - 1);
-               string_list_split_in_place(&list, sb.buf, '\n', -1);
+               string_list_split_in_place(&list, sb.buf, "\n", -1);
 
                string_list_sort(&list);
 
index 22a41c409263c077843598e4cc51881a52b0ce30..9df2f03ac80de2b9cf977b0d7e252eb904c903f3 100644 (file)
@@ -1,10 +1,13 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "config.h"
+#include "hash.h"
+#include "object-name.h"
+#include "repository.h"
+#include "setup.h"
 #include "submodule-config.h"
 #include "submodule.h"
 
-static void die_usage(int argc, const char **argv, const char *msg)
+static void die_usage(int argc UNUSED, const char **argv, const char *msg)
 {
        fprintf(stderr, "%s\n", msg);
        fprintf(stderr, "Usage: %s [<commit> <submodulepath>] ...\n", argv[0]);
@@ -42,7 +45,7 @@ int cmd__submodule_config(int argc, const char **argv)
 
                if (commit[0] == '\0')
                        oidclr(&commit_oid);
-               else if (get_oid(commit, &commit_oid) < 0)
+               else if (repo_get_oid(the_repository, commit, &commit_oid) < 0)
                        die_usage(argc, argv, "Commit not found.");
 
                if (lookup_name) {
index dc1c14bde3741715f9dee0768f061e31ba2d7330..ecd40ded995c0f88b2b58de0d08fd2a1831fca26 100644 (file)
@@ -1,4 +1,6 @@
 #include "test-tool.h"
+#include "repository.h"
+#include "setup.h"
 #include "submodule-config.h"
 
 static void die_usage(const char **argv, const char *msg)
index e060cc6226895d750ced2cab19cedb46f97843b9..356e0a26c5a0b87714d76f608a917807f69599f5 100644 (file)
@@ -1,8 +1,9 @@
 #include "test-tool.h"
 #include "test-tool-utils.h"
-#include "cache.h"
 #include "parse-options.h"
 #include "remote.h"
+#include "repository.h"
+#include "setup.h"
 #include "submodule-config.h"
 #include "submodule.h"
 
@@ -174,7 +175,7 @@ static int cmd__submodule_config_unset(int argc, const char **argv)
        usage_with_options(usage, options);
 }
 
-static int cmd__submodule_config_writeable(int argc, const char **argv)
+static int cmd__submodule_config_writeable(int argc, const char **argv UNUSED)
 {
        struct option options[] = {
                OPT_END()
index ff22f2fa2c57efbda1246f1aab0da494eb026fd1..c344f1694df28da085340b5f556ecae9bfcbb56f 100644 (file)
@@ -1,6 +1,6 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "run-command.h"
+#include "setup.h"
 
 int cmd__subprocess(int argc, const char **argv)
 {
index f374c21ec32ecc049bace6821d5630e103b8937c..20c7495f38593550a8a4dd35a957cc62cf3a2ded 100644 (file)
@@ -1,9 +1,10 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "strvec.h"
 #include "run-command.h"
 #include "exec-cmd.h"
 #include "config.h"
+#include "repository.h"
+#include "trace2.h"
 
 typedef int(fn_unit_test)(int argc, const char **argv);
 
@@ -208,7 +209,7 @@ static int ut_007BUG(int argc, const char **argv)
        BUG("the bug message");
 }
 
-static int ut_008bug(int argc, const char **argv)
+static int ut_008bug(int argc UNUSED, const char **argv UNUSED)
 {
        bug("a bug message");
        bug("another bug message");
@@ -216,7 +217,7 @@ static int ut_008bug(int argc, const char **argv)
        return 0;
 }
 
-static int ut_009bug_BUG(int argc, const char **argv)
+static int ut_009bug_BUG(int argc UNUSED, const char **argv UNUSED)
 {
        bug("a bug message");
        bug("another bug message");
@@ -224,7 +225,7 @@ static int ut_009bug_BUG(int argc, const char **argv)
        return 0;
 }
 
-static int ut_010bug_BUG(int argc, const char **argv)
+static int ut_010bug_BUG(int argc UNUSED, const char **argv UNUSED)
 {
        bug("a %s message", "bug");
        BUG("a %s message", "BUG");
index a2b56b9cae5e3736220afcc30919d1c8bca0b69a..0ce31ce59f54fe972b2d8c1fd16af6bb5a2c24fd 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "setup.h"
 #include "userdiff.h"
 #include "config.h"
 
@@ -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 2c103d1824cfc7f035aea4a6453c9706f9b4491e..b4ff5f986ae00b099ead5d75e5e8b196de88f67c 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "wildmatch.h"
 
 int cmd__wildmatch(int argc, const char **argv)
 {
index 7d45cd61e820305615f4c53157e39074adcb0a50..f084034d38e0328e0792d096225c31ddd91d74c7 100644 (file)
@@ -1,7 +1,9 @@
 #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"
 
 int cmd__write_cache(int argc, const char **argv)
 {
index a648bbd961c2361ea8fa2385cb3f63a002e634c3..b2f330d1a44542065a8fc79e9eb6bf2b9f5ed8a9 100644 (file)
@@ -6,7 +6,7 @@ static const char *utf8_replace_character = "&#xfffd;";
  * Encodes (possibly incorrect) UTF-8 on <stdin> to <stdout>, to be embedded
  * in an XML file.
  */
-int cmd__xml_encode(int argc, const char **argv)
+int cmd__xml_encode(int argc UNUSED, const char **argv UNUSED)
 {
        unsigned char buf[1024], tmp[4], *tmp2 = NULL;
        ssize_t cur = 0, len = 1, remaining = 0;
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 5ea8bc9f1dcfe644da4b9ce720f2a523ff172475..032b2d8fcc48aa2cd72c60fa05f9b1299680f92c 100644 (file)
@@ -43,6 +43,11 @@ 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 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
@@ -166,6 +171,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
@@ -220,6 +268,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
@@ -270,6 +343,66 @@ helper_test() {
                password=
                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))
+       LONG_VALUE=$(perl -e 'print "a" x shift' $LONG_VALUE_LEN)
+
+       test_expect_success "helper ($HELPER) not confused by long header" '
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=victim.example.com
+               username=user
+               password=to-be-stolen
+               EOF
+
+               check fill $HELPER <<-EOF
+               protocol=https
+               host=badguy.example.com
+               wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com
+               --
+               protocol=https
+               host=badguy.example.com
+               username=askpass-username
+               password=askpass-password
+               wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com
+               --
+               askpass: Username for '\''https://badguy.example.com'\'':
+               askpass: Password for '\''https://askpass-username@badguy.example.com'\'':
+               EOF
+       '
 }
 
 helper_test_timeout() {
@@ -298,6 +431,35 @@ helper_test_timeout() {
        '
 }
 
+helper_test_oauth_refresh_token() {
+       HELPER=$1
+
+       test_expect_success "helper ($HELPER) stores oauth_refresh_token" '
+               check approve $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user4
+               password=pass
+               oauth_refresh_token=xyzzy
+               EOF
+       '
+
+       test_expect_success "helper ($HELPER) gets oauth_refresh_token" '
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user4
+               --
+               protocol=https
+               host=example.com
+               username=user4
+               password=pass
+               oauth_refresh_token=xyzzy
+               --
+               EOF
+       '
+}
+
 write_script askpass <<\EOF
 echo >&2 askpass: $*
 what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z)
index a8f5d3274a5a6007ca9acb3317752c6c1c7982a0..c4dc2d46dc1ef4d3c95bda858d208045ded864c2 100644 (file)
@@ -112,15 +112,36 @@ EOF
 
        STRATEGY=$1
 
-       test_expect_success "$STRATEGY diff from attributes" '
+       test_expect_success "setup attributes files for tests with $STRATEGY" '
+               git checkout -b master &&
                echo "file* diff=driver" >.gitattributes &&
-               git config diff.driver.algorithm "$STRATEGY" &&
-               test_must_fail git diff --no-index file1 file2 > output &&
-               cat expect &&
-               cat output &&
+               git add file1 file2 .gitattributes &&
+               git commit -m "adding files" &&
+               git checkout -b branchA &&
+               echo "file* diff=driverA" >.gitattributes &&
+               git add .gitattributes &&
+               git commit -m "adding driverA as diff driver" &&
+               git checkout master &&
+               git clone --bare --no-local . bare.git
+       '
+
+       test_expect_success "$STRATEGY diff from attributes" '
+               test_must_fail git -c diff.driver.algorithm=$STRATEGY diff --no-index file1 file2 > output &&
                test_cmp expect output
        '
 
+       test_expect_success "diff from attributes with bare repo with source" '
+               git -C bare.git --attr-source=branchA -c diff.driver.algorithm=myers \
+                       -c diff.driverA.algorithm=$STRATEGY \
+                       diff HEAD:file1 HEAD:file2 >output &&
+               test_cmp expect output
+       '
+
+       test_expect_success "diff from attributes with bare repo with invalid source" '
+               test_must_fail git -C bare.git --attr-source=invalid-branch diff \
+                       HEAD:file1 HEAD:file2
+       '
+
        test_expect_success "$STRATEGY diff from attributes has valid diffstat" '
                echo "file* diff=driver" >.gitattributes &&
                git config diff.driver.algorithm "$STRATEGY" &&
index 114785586abde524fb13cb29e4b1f357ae9a3286..4eebd9c2b50f0445b975c46bc660efc9eb90ecd5 100644 (file)
@@ -51,6 +51,27 @@ test_lazy_prereq GPG '
        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 &&
+               gpg --homedir "${GNUPGHOME}" --import-ownertrust \
+                       "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
+               gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null \
+                       --sign -u committer@example.com
+               ;;
+       esac
+'
+
 test_lazy_prereq GPGSM '
        test_have_prereq GPG &&
        # Available key info:
@@ -135,8 +156,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 09cf5ed0120bcb35119655596d2a24114363ee48..2fb1b2ae5613a5384dea41df405658cdb787117b 100644 (file)
@@ -142,6 +142,7 @@ prepare_httpd() {
        install_script error-smart-http.sh
        install_script error.sh
        install_script apply-one-time-perl.sh
+       install_script nph-custom-auth.sh
 
        ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
 
@@ -190,6 +191,20 @@ enable_http2 () {
        test_set_prereq HTTP2
 }
 
+enable_cgipassauth () {
+       # We are looking for 2.4.13 or more recent. Since we only support
+       # 2.4 and up, no need to check for older major/minor.
+       if test "$HTTPD_VERSION_MAJOR" = 2 &&
+          test "$HTTPD_VERSION_MINOR" = 4 &&
+          test "$(echo $HTTPD_VERSION | cut -d. -f3)" -lt 13
+       then
+               echo >&4 "apache $HTTPD_VERSION too old for CGIPassAuth"
+               return
+       fi
+       HTTPD_PARA="$HTTPD_PARA -DUSE_CGIPASSAUTH"
+       test_set_prereq CGIPASSAUTH
+}
+
 start_httpd() {
        prepare_httpd >&3 2>&4
 
@@ -227,8 +242,12 @@ test_http_push_nonff () {
                git commit -a -m path2 --amend &&
 
                test_must_fail git push -v origin >output 2>&1 &&
-               (cd "$REMOTE_REPO" &&
-                test $HEAD = $(git rev-parse --verify HEAD))
+               (
+                       cd "$REMOTE_REPO" &&
+                       echo "$HEAD" >expect &&
+                       git rev-parse --verify HEAD >actual &&
+                       test_cmp expect actual
+               )
        '
 
        test_expect_success 'non-fast-forward push show ref status' '
index 31f82fa0934dd545af91e7659e043ffaff740aef..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
@@ -101,6 +102,8 @@ PassEnv LC_ALL
 Alias /dumb/ www/
 Alias /auth/dumb/ www/auth/dumb/
 
+SetEnv PERL_PATH ${PERL_PATH}
+
 <LocationMatch /smart/>
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
        SetEnv GIT_HTTP_EXPORT_ALL
@@ -141,6 +144,13 @@ Alias /auth/dumb/ www/auth/dumb/
        SetEnv GIT_HTTP_EXPORT_ALL
        SetEnv GIT_PROTOCOL
 </LocationMatch>
+<LocationMatch /custom_auth/>
+       SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+       SetEnv GIT_HTTP_EXPORT_ALL
+       <IfDefine USE_CGIPASSAUTH>
+       CGIPassAuth on
+       </IfDefine>
+</LocationMatch>
 ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/
 ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/
 ScriptAlias /smart/no_report/git-receive-pack error-no-report.sh/
@@ -150,6 +160,7 @@ ScriptAlias /broken_smart/ broken-smart-http.sh/
 ScriptAlias /error_smart/ error-smart-http.sh/
 ScriptAlias /error/ error.sh/
 ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
+ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Directory ${GIT_EXEC_PATH}>
        Options FollowSymlinks
 </Directory>
index 09a0abdff7c4775f5ba5fd50f5753b3aed35d60b..d7f9fed6aee8b2a8a665f74507fc1ae41065d22f 100644 (file)
@@ -13,7 +13,7 @@ then
        export LC_ALL
 
        "$GIT_EXEC_PATH/git-http-backend" >out
-       perl -pe "$(cat one-time-perl)" out >out_modified
+       "$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified
 
        if cmp -s out out_modified
        then
diff --git a/t/lib-httpd/nph-custom-auth.sh b/t/lib-httpd/nph-custom-auth.sh
new file mode 100644 (file)
index 0000000..f5345e7
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+VALID_CREDS_FILE=custom-auth.valid
+CHALLENGE_FILE=custom-auth.challenge
+
+#
+# If $VALID_CREDS_FILE exists in $HTTPD_ROOT_PATH, consider each line as a valid
+# credential for the current request. Each line in the file is considered a
+# valid HTTP Authorization header value. For example:
+#
+# Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+#
+# If $CHALLENGE_FILE exists in $HTTPD_ROOT_PATH, output the contents as headers
+# in a 401 response if no valid authentication credentials were included in the
+# request. For example:
+#
+# WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+# WWW-Authenticate: Basic realm="example.com"
+#
+
+if test -n "$HTTP_AUTHORIZATION" && \
+       grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE"
+then
+       # Note that although git-http-backend returns a status line, it
+       # does so using a CGI 'Status' header. Because this script is an
+       # No Parsed Headers (NPH) script, we must return a real HTTP
+       # status line.
+       # This is only a test script, so we don't bother to check for
+       # the actual status from git-http-backend and always return 200.
+       echo 'HTTP/1.1 200 OK'
+       exec "$GIT_EXEC_PATH"/git-http-backend
+fi
+
+echo 'HTTP/1.1 401 Authorization Required'
+if test -f "$CHALLENGE_FILE"
+then
+       cat "$CHALLENGE_FILE"
+fi
+echo
index cfd76bf987bd902503cfcacd3e8ac1b9c4deb09c..89ca1f7805547eec1f4ee8e90c1afefc30b35da6 100644 (file)
@@ -29,8 +29,12 @@ set_and_save_state () {
 
 # verify_state <path> <expected-worktree-content> <expected-index-content>
 verify_state () {
-       test "$(cat "$1")" = "$2" &&
-       test "$(git show :"$1")" = "$3"
+       echo "$2" >expect &&
+       test_cmp expect "$1" &&
+
+       echo "$3" >expect &&
+       git show :"$1" >actual &&
+       test_cmp expect actual
 }
 
 # verify_saved_state <path>
@@ -46,5 +50,6 @@ save_head () {
 }
 
 verify_saved_head () {
-       test "$(cat _head)" = "$(git rev-parse HEAD)"
+       git rev-parse HEAD >actual &&
+       test_cmp _head actual
 }
index 2d31fcfda1f338973cfc868b7f01ae925b39d326..9acb0d5d19d2ec44827856a7496a2f785c537e02 100644 (file)
@@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () {
 # Note that this only supports submodules at the root level of the
 # superproject, with the default name, i.e. same as its path.
 test_git_directory_is_unchanged () {
-       (
-               cd ".git/modules/$1" &&
-               # does core.worktree point at the right place?
-               test "$(git config core.worktree)" = "../../../$1" &&
-               # remove it temporarily before comparing, as
-               # "$1/.git/config" lacks it...
-               git config --unset core.worktree
-       ) &&
+       # does core.worktree point at the right place?
+       echo "../../../$1" >expect &&
+       git -C ".git/modules/$1" config core.worktree >actual &&
+       test_cmp expect actual &&
+       # remove it temporarily before comparing, as
+       # "$1/.git/config" lacks it...
+       git -C ".git/modules/$1" config --unset core.worktree &&
        diff -r ".git/modules/$1" "$1/.git" &&
-       (
-               # ... and then restore.
-               cd ".git/modules/$1" &&
-               git config core.worktree "../../../$1"
-       )
+       # ... and then restore.
+       git -C ".git/modules/$1" config core.worktree "../../../$1"
 }
 
 test_git_directory_exists () {
@@ -189,7 +185,9 @@ test_git_directory_exists () {
        if test -f sub1/.git
        then
                # does core.worktree point at the right place?
-               test "$(git -C .git/modules/$1 config core.worktree)" = "../../../$1"
+               echo "../../../$1" >expect &&
+               git -C ".git/modules/$1" config core.worktree >actual &&
+               test_cmp expect actual
        fi
 }
 
@@ -804,7 +802,7 @@ test_submodule_recursing_with_args_common () {
                        git branch -t no_submodule origin/no_submodule &&
                        $command no_submodule &&
                        test_superproject_content origin/no_submodule &&
-                       ! test_path_is_dir sub1 &&
+                       test_path_is_missing sub1 &&
                        test_must_fail git config -f .git/modules/sub1/config core.worktree &&
                        test_must_fail git config -f .git/modules/sub1/modules/sub2/config core.worktree
                )
diff --git a/t/perf/p1500-graph-walks.sh b/t/perf/p1500-graph-walks.sh
new file mode 100755 (executable)
index 0000000..e14e762
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='Commit walk performance tests'
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+test_expect_success 'setup' '
+       git for-each-ref --format="%(refname)" "refs/heads/*" "refs/tags/*" >allrefs &&
+       sort -r allrefs | head -n 50 >refs &&
+       for ref in $(cat refs)
+       do
+               git branch -f ref-$ref $ref &&
+               echo ref-$ref ||
+               return 1
+       done >branches &&
+       for ref in $(cat refs)
+       do
+               git tag -f tag-$ref $ref &&
+               echo tag-$ref ||
+               return 1
+       done >tags &&
+       git commit-graph write --reachable
+'
+
+test_perf 'ahead-behind counts: git for-each-ref' '
+       git for-each-ref --format="%(ahead-behind:HEAD)" --stdin <refs
+'
+
+test_perf 'ahead-behind counts: git branch' '
+       xargs git branch -l --format="%(ahead-behind:HEAD)" <branches
+'
+
+test_perf 'ahead-behind counts: git tag' '
+       xargs git tag -l --format="%(ahead-behind:HEAD)" <tags
+'
+
+test_perf 'contains: git for-each-ref --merged' '
+       git for-each-ref --merged=HEAD --stdin <refs
+'
+
+test_perf 'contains: git branch --merged' '
+       xargs git branch --merged=HEAD <branches
+'
+
+test_perf 'contains: git tag --merged' '
+       xargs git tag --merged=HEAD <tags
+'
+
+test_done
index 3242cfe91a096fef06d11cc589bb1ab415135e96..96ed3e1d69881541c82bdaf8c7f6b6fd8af97ef5 100755 (executable)
@@ -43,6 +43,7 @@ test_expect_success 'setup repo and indexes' '
        done &&
 
        git sparse-checkout init --cone &&
+       git tag -a v1.0 -m "Final" &&
        git sparse-checkout set $SPARSE_CONE &&
        git checkout -b wide $OLD_COMMIT &&
 
@@ -124,6 +125,14 @@ test_perf_on_all git read-tree -mu HEAD
 test_perf_on_all git checkout-index -f --all
 test_perf_on_all git update-index --add --remove $SPARSE_CONE/a
 test_perf_on_all "git rm -f $SPARSE_CONE/a && git checkout HEAD -- $SPARSE_CONE/a"
-test_perf_on_all git grep --cached --sparse bogus -- "f2/f1/f1/*"
+test_perf_on_all git grep --cached bogus -- "f2/f1/f1/*"
+test_perf_on_all git write-tree
+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_done
index 0684b690af020442847d2ef94162f311e20abc8a..ceec60656b59119c2bb82651f8ae6057899f41c5 100755 (executable)
@@ -12,8 +12,7 @@ test_lookup_pack_bitmap () {
        test_perf_large_repo
 
        test_expect_success 'setup bitmap config' '
-               git config pack.writebitmaps true &&
-               git config pack.writeReverseIndex true
+               git config pack.writebitmaps true
        '
 
        # we need to create the tag up front such that it is covered by the repack and
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 d479303efa03df6f818496f1cdcafe390bee0126..30a6edca1d29fcef63cfc155685600c63553f636 100755 (executable)
@@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' '
 test_expect_success 'branch -m with the initial branch' '
        git init rename-initial &&
        git -C rename-initial branch -m renamed &&
-       test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
+       echo renamed >expect &&
+       git -C rename-initial symbolic-ref --short HEAD >actual &&
+       test_cmp expect actual &&
+
        git -C rename-initial branch -m renamed again &&
-       test again = $(git -C rename-initial symbolic-ref --short HEAD)
+       echo again >expect &&
+       git -C rename-initial symbolic-ref --short HEAD >actual &&
+       test_cmp expect actual
 '
 
 test_done
index 26eaca095a26a6a654364bdd8acf208af30b2d00..e013d38f485cc8b06c1afb51579ed6a4d322dfaa 100755 (executable)
@@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' '
 
 test_expect_success 'final setup + check rev-parse --git-dir' '
        echo "gitdir: $REAL" >.git &&
-       test "$REAL" = "$(git rev-parse --git-dir)"
+       echo "$REAL" >expect &&
+       git rev-parse --git-dir >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'check hash-object' '
index 89b306cb114debb61e787e6d80417cd362cc367f..26e082f05b4473a553b4de9b7747b928179439cd 100755 (executable)
@@ -30,8 +30,17 @@ attr_check_quote () {
 attr_check_source () {
        path="$1" expect="$2" source="$3" git_opts="$4" &&
 
-       git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
        echo "$path: test: $expect" >expect &&
+
+       git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
+       test_cmp expect actual &&
+       test_must_be_empty err &&
+
+       git $git_opts --attr-source="$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
 }
index eeb8539c1bcb2df86a5aff1fa2c78fc555598d14..8cb597f99c4cead2388681416d3cc0eddd90fa0f 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,6 +242,28 @@ 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
 '
index 35cc8c3b39896cb5caf6740d6847f5dec66e1dea..81946e87ccb9b478789164a6db54d9a80278288d 100755 (executable)
@@ -125,7 +125,7 @@ test_expect_success 'update with autocrlf=input' '
        munge_cr append dir/two &&
        git update-index -- one dir/two &&
        differs=$(git diff-index --cached HEAD) &&
-       verbose test -z "$differs"
+       test -z "$differs"
 
 '
 
@@ -138,7 +138,7 @@ test_expect_success 'update with autocrlf=true' '
        munge_cr append dir/two &&
        git update-index -- one dir/two &&
        differs=$(git diff-index --cached HEAD) &&
-       verbose test -z "$differs"
+       test -z "$differs"
 
 '
 
@@ -153,7 +153,7 @@ test_expect_success 'checkout with autocrlf=true' '
        test "$one" = $(git hash-object --stdin <one) &&
        test "$two" = $(git hash-object --stdin <dir/two) &&
        differs=$(git diff-index --cached HEAD) &&
-       verbose test -z "$differs"
+       test -z "$differs"
 '
 
 test_expect_success 'checkout with autocrlf=input' '
@@ -167,7 +167,7 @@ test_expect_success 'checkout with autocrlf=input' '
        test "$one" = $(git hash-object --stdin <one) &&
        test "$two" = $(git hash-object --stdin <dir/two) &&
        differs=$(git diff-index --cached HEAD) &&
-       verbose test -z "$differs"
+       test -z "$differs"
 '
 
 test_expect_success 'apply patch (autocrlf=input)' '
@@ -177,7 +177,7 @@ test_expect_success 'apply patch (autocrlf=input)' '
        git read-tree --reset -u HEAD &&
 
        git apply patch.file &&
-       verbose test "$patched" = "$(git hash-object --stdin <one)"
+       test "$patched" = "$(git hash-object --stdin <one)"
 '
 
 test_expect_success 'apply patch --cached (autocrlf=input)' '
@@ -187,7 +187,7 @@ test_expect_success 'apply patch --cached (autocrlf=input)' '
        git read-tree --reset -u HEAD &&
 
        git apply --cached patch.file &&
-       verbose test "$patched" = $(git rev-parse :one)
+       test "$patched" = $(git rev-parse :one)
 '
 
 test_expect_success 'apply patch --index (autocrlf=input)' '
@@ -197,8 +197,8 @@ test_expect_success 'apply patch --index (autocrlf=input)' '
        git read-tree --reset -u HEAD &&
 
        git apply --index patch.file &&
-       verbose test "$patched" = $(git rev-parse :one) &&
-       verbose test "$patched" = $(git hash-object --stdin <one)
+       test "$patched" = $(git rev-parse :one) &&
+       test "$patched" = $(git hash-object --stdin <one)
 '
 
 test_expect_success 'apply patch (autocrlf=true)' '
@@ -208,7 +208,7 @@ test_expect_success 'apply patch (autocrlf=true)' '
        git read-tree --reset -u HEAD &&
 
        git apply patch.file &&
-       verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
+       test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
 '
 
 test_expect_success 'apply patch --cached (autocrlf=true)' '
@@ -218,7 +218,7 @@ test_expect_success 'apply patch --cached (autocrlf=true)' '
        git read-tree --reset -u HEAD &&
 
        git apply --cached patch.file &&
-       verbose test "$patched" = $(git rev-parse :one)
+       test "$patched" = $(git rev-parse :one)
 '
 
 test_expect_success 'apply patch --index (autocrlf=true)' '
@@ -228,8 +228,8 @@ test_expect_success 'apply patch --index (autocrlf=true)' '
        git read-tree --reset -u HEAD &&
 
        git apply --index patch.file &&
-       verbose test "$patched" = $(git rev-parse :one) &&
-       verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
+       test "$patched" = $(git rev-parse :one) &&
+       test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
 '
 
 test_expect_success '.gitattributes says two is binary' '
@@ -240,7 +240,7 @@ test_expect_success '.gitattributes says two is binary' '
        git read-tree --reset -u HEAD &&
 
        ! has_cr dir/two &&
-       verbose has_cr one &&
+       has_cr one &&
        ! has_cr three
 '
 
@@ -259,8 +259,8 @@ test_expect_success '.gitattributes says two and three are text' '
        echo "t* crlf" >.gitattributes &&
        git read-tree --reset -u HEAD &&
 
-       verbose has_cr dir/two &&
-       verbose has_cr three
+       has_cr dir/two &&
+       has_cr three
 '
 
 test_expect_success 'in-tree .gitattributes (1)' '
@@ -273,7 +273,7 @@ test_expect_success 'in-tree .gitattributes (1)' '
        git read-tree --reset -u HEAD &&
 
        ! has_cr one &&
-       verbose has_cr three
+       has_cr three
 '
 
 test_expect_success 'in-tree .gitattributes (2)' '
@@ -283,7 +283,7 @@ test_expect_success 'in-tree .gitattributes (2)' '
        git checkout-index -f -q -u -a &&
 
        ! has_cr one &&
-       verbose has_cr three
+       has_cr three
 '
 
 test_expect_success 'in-tree .gitattributes (3)' '
@@ -294,7 +294,7 @@ test_expect_success 'in-tree .gitattributes (3)' '
        git checkout-index -u one dir/two three &&
 
        ! has_cr one &&
-       verbose has_cr three
+       has_cr three
 '
 
 test_expect_success 'in-tree .gitattributes (4)' '
@@ -305,7 +305,7 @@ test_expect_success 'in-tree .gitattributes (4)' '
        git checkout-index -u .gitattributes &&
 
        ! has_cr one &&
-       verbose has_cr three
+       has_cr three
 '
 
 test_expect_success 'checkout with existing .gitattributes' '
index a94ac1eae377c023ae3e02eaae393db6e8d232d3..2f57c8669cb5af3dd6fc79bfca4b486f50fa4d19 100755 (executable)
@@ -70,7 +70,8 @@ create_NNO_MIX_files () {
                                cp CRLF        ${pfx}_CRLF.txt &&
                                cp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&
                                cp LF_mix_CR   ${pfx}_LF_mix_CR.txt &&
-                               cp CRLF_nul    ${pfx}_CRLF_nul.txt
+                               cp CRLF_nul    ${pfx}_CRLF_nul.txt ||
+                               return 1
                        done
                done
        done
@@ -101,7 +102,8 @@ commit_check_warn () {
        do
                fname=${pfx}_$f.txt &&
                cp $f $fname &&
-               git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
+               git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" ||
+               return 1
        done &&
        git commit -m "core.autocrlf $crlf" &&
        check_warning "$lfname" ${pfx}_LF.err &&
@@ -121,15 +123,19 @@ commit_chk_wrnNNO () {
        lfmixcr=$1 ; shift
        crlfnul=$1 ; shift
        pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}
-       #Commit files on top of existing file
-       create_gitattributes "$attr" $aeol &&
-       for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
-       do
-               fname=${pfx}_$f.txt &&
-               cp $f $fname &&
-               printf Z >>"$fname" &&
-               git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
-       done
+
+       test_expect_success 'setup commit NNO files' '
+               #Commit files on top of existing file
+               create_gitattributes "$attr" $aeol &&
+               for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
+               do
+                       fname=${pfx}_$f.txt &&
+                       cp $f $fname &&
+                       printf Z >>"$fname" &&
+                       git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" ||
+                       return 1
+               done
+       '
 
        test_expect_success "commit NNO files crlf=$crlf attr=$attr LF" '
                check_warning "$lfwarn" ${pfx}_LF.err
@@ -163,15 +169,19 @@ commit_MIX_chkwrn () {
        lfmixcr=$1 ; shift
        crlfnul=$1 ; shift
        pfx=MIX_attr_${attr}_aeol_${aeol}_${crlf}
-       #Commit file with CLRF_mix_LF on top of existing file
-       create_gitattributes "$attr" $aeol &&
-       for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
-       do
-               fname=${pfx}_$f.txt &&
-               cp CRLF_mix_LF $fname &&
-               printf Z >>"$fname" &&
-               git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
-       done
+
+       test_expect_success 'setup commit file with mixed EOL' '
+               #Commit file with CLRF_mix_LF on top of existing file
+               create_gitattributes "$attr" $aeol &&
+               for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
+               do
+                       fname=${pfx}_$f.txt &&
+                       cp CRLF_mix_LF $fname &&
+                       printf Z >>"$fname" &&
+                       git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" ||
+                       return 1
+               done
+       '
 
        test_expect_success "commit file with mixed EOL onto LF crlf=$crlf attr=$attr" '
                check_warning "$lfwarn" ${pfx}_LF.err
@@ -289,17 +299,17 @@ checkout_files () {
        lfmixcrlf=$1 ; shift
        lfmixcr=$1 ; shift
        crlfnul=$1 ; shift
-       create_gitattributes "$attr" $ident $aeol &&
-       git config core.autocrlf $crlf &&
+       test_expect_success "setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf" '
+               create_gitattributes "$attr" $ident $aeol &&
+               git config core.autocrlf $crlf
+       '
        pfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&
        for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul
        do
-               rm crlf_false_attr__$f.txt &&
-               if test -z "$ceol"; then
-                       git checkout -- crlf_false_attr__$f.txt
-               else
-                       git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt
-               fi
+               test_expect_success "setup $f checkout ${ceol:+ with -c core.eol=$ceol}"  '
+                       rm -f crlf_false_attr__$f.txt &&
+                       git ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt
+               '
        done
 
        test_expect_success "ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol" '
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 11c15a48aab57ee81245a933f5dfdab5210103a5..038b8b788d7dea688c2efa807e1d1856b8f33c13 100755 (executable)
@@ -7,13 +7,26 @@ TEST_PASSES_SANITIZE_LEAK=true
 
 pwd="$(pwd)"
 
-expect_accepted () {
-       git "$@" rev-parse --git-dir
+expect_accepted_implicit () {
+       test_when_finished 'rm "$pwd/trace.perf"' &&
+       GIT_TRACE2_PERF="$pwd/trace.perf" git "$@" rev-parse --git-dir &&
+       # Note: we're intentionally only checking that the bare repo has a
+       # directory *prefix* of $pwd
+       grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
+}
+
+expect_accepted_explicit () {
+       test_when_finished 'rm "$pwd/trace.perf"' &&
+       GIT_DIR="$1" GIT_TRACE2_PERF="$pwd/trace.perf" git rev-parse --git-dir &&
+       ! grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
 }
 
 expect_rejected () {
-       test_must_fail git "$@" rev-parse --git-dir 2>err &&
-       grep -F "cannot use bare repository" err
+       test_when_finished 'rm "$pwd/trace.perf"' &&
+       test_env GIT_TRACE2_PERF="$pwd/trace.perf" \
+               test_must_fail git "$@" rev-parse --git-dir 2>err &&
+       grep -F "cannot use bare repository" err &&
+       grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
 }
 
 test_expect_success 'setup bare repo in worktree' '
@@ -22,12 +35,13 @@ test_expect_success 'setup bare repo in worktree' '
 '
 
 test_expect_success 'safe.bareRepository unset' '
-       expect_accepted -C outer-repo/bare-repo
+       test_unconfig --global safe.bareRepository &&
+       expect_accepted_implicit -C outer-repo/bare-repo
 '
 
 test_expect_success 'safe.bareRepository=all' '
        test_config_global safe.bareRepository all &&
-       expect_accepted -C outer-repo/bare-repo
+       expect_accepted_implicit -C outer-repo/bare-repo
 '
 
 test_expect_success 'safe.bareRepository=explicit' '
@@ -47,7 +61,7 @@ test_expect_success 'safe.bareRepository in the repository' '
 
 test_expect_success 'safe.bareRepository on the command line' '
        test_config_global safe.bareRepository explicit &&
-       expect_accepted -C outer-repo/bare-repo \
+       expect_accepted_implicit -C outer-repo/bare-repo \
                -c safe.bareRepository=all
 '
 
@@ -60,4 +74,8 @@ test_expect_success 'safe.bareRepository in included file' '
        expect_rejected -C outer-repo/bare-repo
 '
 
+test_expect_success 'no trace when GIT_DIR is explicitly provided' '
+       expect_accepted_explicit "$pwd/outer-repo/bare-repo"
+'
+
 test_done
index 7d7ecfd57162cf9cde2e74007a6323c635a3b2a9..e19a19963697a08255bb1b933631cdc90d57340d 100755 (executable)
@@ -30,11 +30,12 @@ usage: test-tool parse-options <options>
     -F, --file <file>     set file to <file>
 
 String options
-    -s, --string <string>
-                          get a string
+    -s, --string <string> get a string
     --string2 <str>       get another string
     --st <st>             get another string (pervert ordering)
     -o <str>              get another string
+    --longhelp            help text of this entry
+                          spans multiple lines
     --list <str>          add str to list
 
 Magic arguments
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 ' '
index 6bada3702257649551558884237f71bea3fdadc2..c3eb1158ef9ae2eb10f3f7a6d5c882e41f3c576a 100755 (executable)
@@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup '
 
 test_expect_success SYMLINKS 'update-index --add beyond symlinks' '
        test_must_fail git update-index --add c/d &&
-       ! ( git ls-files | grep c/d )
+       cat >expect <<-\EOF &&
+       a
+       b/d
+       EOF
+       git ls-files >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success SYMLINKS 'add beyond symlinks' '
        test_must_fail git add c/d &&
-       ! ( git ls-files | grep c/d )
+       cat >expect <<-\EOF &&
+       a
+       b/d
+       EOF
+       git ls-files >actual &&
+       test_cmp expect actual
 '
 
 test_done
index 68e29c904a62c9ef51d6a1bfc3449795d50ac10f..0afa3d0d312ca6d1788b76d3b0dfcba04f8397e7 100755 (executable)
@@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true
 
 norm_path() {
        expected=$(test-tool path-utils print_path "$2")
-       test_expect_success $3 "normalize path: $1 => $2" \
-       "test \"\$(test-tool path-utils normalize_path_copy '$1')\" = '$expected'"
+       test_expect_success $3 "normalize path: $1 => $2" "
+               echo '$expected' >expect &&
+               test-tool path-utils normalize_path_copy '$1' >actual &&
+               test_cmp expect actual
+       "
 }
 
 relative_path() {
        expected=$(test-tool path-utils print_path "$3")
-       test_expect_success $4 "relative path: $1 $2 => $3" \
-       "test \"\$(test-tool path-utils relative_path '$1' '$2')\" = '$expected'"
+       test_expect_success $4 "relative path: $1 $2 => $3" "
+               echo '$expected' >expect &&
+               test-tool path-utils relative_path '$1' '$2' >actual &&
+               test_cmp expect actual
+       "
 }
 
 test_submodule_relative_url() {
        test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
-               actual=\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&
-               test \"\$actual\" = '$4'
+               echo '$4' >expect &&
+               test-tool submodule resolve-relative-url '$1' '$2' '$3' >actual &&
+               test_cmp expect actual
        "
 }
 
@@ -64,9 +71,11 @@ ancestor() {
                expected=$(($expected-$rootslash+$rootoff))
                ;;
        esac
-       test_expect_success $4 "longest ancestor: $1 $2 => $expected" \
-       "actual=\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&
-        test \"\$actual\" = '$expected'"
+       test_expect_success $4 "longest ancestor: $1 $2 => $expected" "
+               echo '$expected' >expect &&
+               test-tool path-utils longest_ancestor_length '$1' '$2' >actual &&
+               test_cmp expect actual
+       "
 }
 
 # Some absolute path tests should be skipped on Windows due to path mangling
@@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW
 ancestor //server/share/my-directory //server/share/ 14 MINGW
 
 test_expect_success 'strip_path_suffix' '
-       test c:/msysgit = $(test-tool path-utils strip_path_suffix \
-               c:/msysgit/libexec//git-core libexec/git-core)
+       echo c:/msysgit >expect &&
+       test-tool path-utils strip_path_suffix \
+               c:/msysgit/libexec//git-core libexec/git-core >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'absolute path rejects the empty string' '
@@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' '
 '
 
 test_expect_success POSIX 'real path works on absolute paths 1' '
+       echo / >expect &&
+       test-tool path-utils real_path "/" >actual &&
+       test_cmp expect actual &&
+
        nopath="hopefully-absent-path" &&
-       test "/" = "$(test-tool path-utils real_path "/")" &&
-       test "/$nopath" = "$(test-tool path-utils real_path "/$nopath")"
+       echo "/$nopath" >expect &&
+       test-tool path-utils real_path "/$nopath" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'real path works on absolute paths 2' '
-       nopath="hopefully-absent-path" &&
        # Find an existing top-level directory for the remaining tests:
        d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
-       test "$d" = "$(test-tool path-utils real_path "$d")" &&
-       test "$d/$nopath" = "$(test-tool path-utils real_path "$d/$nopath")"
+       echo "$d" >expect &&
+       test-tool path-utils real_path "$d" >actual &&
+       test_cmp expect actual &&
+
+       nopath="hopefully-absent-path" &&
+       echo "$d/$nopath" >expect &&
+       test-tool path-utils real_path "$d/$nopath" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success POSIX 'real path removes extra leading slashes' '
+       echo "/" >expect &&
+       test-tool path-utils real_path "///" >actual &&
+       test_cmp expect actual &&
+
        nopath="hopefully-absent-path" &&
-       test "/" = "$(test-tool path-utils real_path "///")" &&
-       test "/$nopath" = "$(test-tool path-utils real_path "///$nopath")" &&
+       echo "/$nopath" >expect &&
+       test-tool path-utils real_path "///$nopath" >actual &&
+       test_cmp expect actual &&
+
        # Find an existing top-level directory for the remaining tests:
        d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
-       test "$d" = "$(test-tool path-utils real_path "//$d")" &&
-       test "$d/$nopath" = "$(test-tool path-utils real_path "//$d/$nopath")"
+       echo "$d" >expect &&
+       test-tool path-utils real_path "//$d" >actual &&
+       test_cmp expect actual &&
+
+       echo "$d/$nopath" >expect &&
+       test-tool path-utils real_path "//$d/$nopath" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'real path removes other extra slashes' '
-       nopath="hopefully-absent-path" &&
        # Find an existing top-level directory for the remaining tests:
        d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") &&
-       test "$d" = "$(test-tool path-utils real_path "$d///")" &&
-       test "$d/$nopath" = "$(test-tool path-utils real_path "$d///$nopath")"
+       echo "$d" >expect &&
+       test-tool path-utils real_path "$d///" >actual &&
+       test_cmp expect actual &&
+
+       nopath="hopefully-absent-path" &&
+       echo "$d/$nopath" >expect &&
+       test-tool path-utils real_path "$d///$nopath" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success SYMLINKS 'real path works on symlinks' '
@@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
        mkdir third &&
        dir="$(cd .git && pwd -P)" &&
        dir2=third/../second/other/.git &&
-       test "$dir" = "$(test-tool path-utils real_path $dir2)" &&
+       echo "$dir" >expect &&
+       test-tool path-utils real_path $dir2 >actual &&
+       test_cmp expect actual &&
        file="$dir"/index &&
-       test "$file" = "$(test-tool path-utils real_path $dir2/index)" &&
+       echo "$file" >expect &&
+       test-tool path-utils real_path $dir2/index >actual &&
+       test_cmp expect actual &&
        basename=blub &&
-       test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" &&
+       echo "$dir/$basename" >expect &&
+       test-tool -C .git path-utils real_path "$basename" >actual &&
+       test_cmp expect actual &&
        ln -s ../first/file .git/syml &&
        sym="$(cd first && pwd -P)"/file &&
-       test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")"
+       echo "$sym" >expect &&
+       test-tool path-utils real_path "$dir2/syml" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
        ln -s target symlink &&
-       test "$(test-tool path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink"
+       echo "symlink" >expect &&
+       test-tool path-utils prefix_path prefix "$(pwd)/symlink" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'prefix_path works with only absolute path to work tree' '
@@ -255,7 +302,10 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin
 test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having  same beginning as work tree' '
        git init repo &&
        ln -s repo repolink &&
-       test "a" = "$(cd repo && test-tool path-utils prefix_path prefix "$(pwd)/../repolink/a")"
+       echo "a" >expect &&
+       repo_path="$(cd repo && pwd)" &&
+       test-tool -C repo path-utils prefix_path prefix "$repo_path/../repolink/a" >actual &&
+       test_cmp expect actual
 '
 
 relative_path /foo/a/b/c/      /foo/a/b/       c/
index 46d4839194bb2322b2a8cd9b80618a855e0fb070..1fee6d90102cc6f9b90786a6324f56e7086b91bf 100755 (executable)
@@ -18,6 +18,14 @@ test_split () {
        "
 }
 
+test_split_in_place() {
+       cat >expected &&
+       test_expect_success "split (in place) $1 at $2, max $3" "
+               test-tool string-list split_in_place '$1' '$2' '$3' >actual &&
+               test_cmp expected actual
+       "
+}
+
 test_split "foo:bar:baz" ":" "-1" <<EOF
 3
 [0]: "foo"
@@ -61,6 +69,49 @@ test_split ":" ":" "-1" <<EOF
 [1]: ""
 EOF
 
+test_split_in_place "foo:;:bar:;:baz:;:" ":;" "-1" <<EOF
+10
+[0]: "foo"
+[1]: ""
+[2]: ""
+[3]: "bar"
+[4]: ""
+[5]: ""
+[6]: "baz"
+[7]: ""
+[8]: ""
+[9]: ""
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "0" <<EOF
+1
+[0]: "foo:;:bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "1" <<EOF
+2
+[0]: "foo"
+[1]: ";:bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "2" <<EOF
+3
+[0]: "foo"
+[1]: ""
+[2]: ":bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:" ":;" "-1" <<EOF
+7
+[0]: "foo"
+[1]: ""
+[2]: ""
+[3]: "bar"
+[4]: ""
+[5]: ""
+[6]: ""
+EOF
+
 test_expect_success "test filter_string_list" '
        test "x-" = "x$(test-tool string-list filter - y)" &&
        test "x-" = "x$(test-tool string-list filter no y)" &&
index 3648d439a87eabb37b581cf5e731f9048085703b..4b90b74d5d515ec80b18b67e2b6f32780f860f22 100755 (executable)
@@ -40,4 +40,23 @@ test_expect_success 'do nothing on empty config' '
        git for-each-repo --config=bogus.config -- help --no-such-option
 '
 
+test_expect_success 'error on bad config keys' '
+       test_expect_code 129 git for-each-repo --config=a &&
+       test_expect_code 129 git for-each-repo --config=a.b. &&
+       test_expect_code 129 git for-each-repo --config="'\''.b"
+'
+
+test_expect_success 'error on NULL value for config keys' '
+       cat >>.git/config <<-\EOF &&
+       [empty]
+               key
+       EOF
+       cat >expect <<-\EOF &&
+       error: missing value for '\''empty.key'\''
+       EOF
+       test_expect_code 129 git for-each-repo --config=empty.key 2>actual.raw &&
+       grep ^error actual.raw >actual &&
+       test_cmp expect actual
+'
+
 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 a16cc3d298357be89e58514db83c1d3f04b3ad4d..70a3223f2199b06833166863e58489ba0f632e59 100755 (executable)
@@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' '
        test_commit A &&
        git checkout -b junk &&
        git checkout - &&
-       test "$(git symbolic-ref HEAD)" = refs/heads/main &&
+       echo refs/heads/main >expect &&
+       git symbolic-ref HEAD >actual &&
+       test_cmp expect actual &&
        git branch -d @{-1} &&
        test_must_fail git rev-parse --verify refs/heads/junk
 '
@@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' '
        git reflog expire --expire=now &&
        git checkout -b junk2 &&
        git checkout - &&
-       test "$(git symbolic-ref HEAD)" = refs/heads/main &&
+       echo refs/heads/main >expect &&
+       git symbolic-ref HEAD >actual &&
+       test_cmp expect actual &&
        test_must_fail git branch -d @{-12} &&
        git rev-parse --verify refs/heads/main
 '
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 c66d91e82d8bc737bc6b909c9427f163aef5dfea..a4f5bba5075c3d61a86b2fad1cb95ba73058bc8e 100755 (executable)
@@ -214,6 +214,24 @@ test_expect_success 'credential_approve stores password expiry' '
        EOF
 '
 
+test_expect_success 'credential_approve stores oauth refresh token' '
+       check approve useless <<-\EOF
+       protocol=http
+       host=example.com
+       username=foo
+       password=bar
+       oauth_refresh_token=xyzzy
+       --
+       --
+       useless: store
+       useless: protocol=http
+       useless: host=example.com
+       useless: username=foo
+       useless: password=bar
+       useless: oauth_refresh_token=xyzzy
+       EOF
+'
+
 test_expect_success 'do not bother storing password-less credential' '
        check approve useless <<-\EOF
        protocol=http
@@ -808,7 +826,7 @@ test_expect_success 'credential config with partial URLs' '
 
        git -c credential.$partial.helper=yep \
                -c credential.with%0anewline.username=uh-oh \
-               credential fill <stdin >stdout 2>stderr &&
+               credential fill <stdin 2>stderr &&
        test_i18ngrep "skipping credential lookup for key" stderr
 '
 
index 698b7159f030905fb63ce4f6856d7ecf49f50b02..c02a3b5969c3d2265d1552132464df7135cd522b 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_oauth_refresh_token cache
 
 test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
        test_when_finished "
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 12e30d77d096d5108396f90ecd4f9088c0f27413..26be4a2b5a007afa7ef1a9bd4438d16173c6aad5 100755 (executable)
@@ -41,7 +41,8 @@ test_expect_success 'reset should remove remnants from a failed merge' '
        git ls-files -s &&
        read_tree_u_must_succeed --reset -u HEAD &&
        git ls-files -s >actual &&
-       ! test -f old
+       ! test -f old &&
+       test_cmp expect actual
 '
 
 test_expect_success 'two-way reset should remove remnants too' '
@@ -56,7 +57,8 @@ test_expect_success 'two-way reset should remove remnants too' '
        git ls-files -s &&
        read_tree_u_must_succeed --reset -u HEAD HEAD &&
        git ls-files -s >actual &&
-       ! test -f old
+       ! test -f old &&
+       test_cmp expect actual
 '
 
 test_expect_success 'Porcelain reset should remove remnants too' '
@@ -71,7 +73,8 @@ test_expect_success 'Porcelain reset should remove remnants too' '
        git ls-files -s &&
        git reset --hard &&
        git ls-files -s >actual &&
-       ! test -f old
+       ! test -f old &&
+       test_cmp expect actual
 '
 
 test_expect_success 'Porcelain checkout -f should remove remnants too' '
@@ -86,7 +89,8 @@ test_expect_success 'Porcelain checkout -f should remove remnants too' '
        git ls-files -s &&
        git checkout -f &&
        git ls-files -s >actual &&
-       ! test -f old
+       ! test -f old &&
+       test_cmp expect actual
 '
 
 test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
@@ -101,7 +105,8 @@ test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
        git ls-files -s &&
        git checkout -f HEAD &&
        git ls-files -s >actual &&
-       ! test -f old
+       ! test -f old &&
+       test_cmp expect actual
 '
 
 test_done
index 2d875b17d8a94a45b9789e3466139adbd6b4c680..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' '
@@ -603,7 +645,8 @@ do
                        fatal: Not a valid object name $(test_oid deadbeef_short)
                        EOF
                        test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef_short) >out 2>err.actual &&
-                       test_must_be_empty out
+                       test_must_be_empty out &&
+                       test_cmp expect.err err.actual
                '
 
                test_expect_success "cat-file $arg1 $arg2 error on missing full OID" '
@@ -839,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
@@ -853,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 &&
@@ -967,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 3c0819452653878ae51779798ce90712dc30a901..22875ba598c2a82bba6c7504c420c690441f7167 100755 (executable)
@@ -60,11 +60,11 @@ test_expect_success 'allow missing object with --missing' '
 '
 
 test_expect_success 'mktree refuses to read ls-tree -r output (1)' '
-       test_must_fail git mktree <all >actual
+       test_must_fail git mktree <all
 '
 
 test_expect_success 'mktree refuses to read ls-tree -r output (2)' '
-       test_must_fail git mktree <all.withsub >actual
+       test_must_fail git mktree <all.withsub
 '
 
 test_done
index 627267be1531056c4eff9e5a0dc2bc1d8d1eab38..9ceb17f911891964aa5e3a2837a2739bead2bc3c 100755 (executable)
@@ -555,7 +555,7 @@ test_expect_success 'cone mode: set with core.ignoreCase=true' '
        check_files repo a folder1
 '
 
-test_expect_success 'interaction with submodules' '
+test_expect_success 'setup submodules' '
        git clone repo super &&
        (
                cd super &&
@@ -566,11 +566,22 @@ test_expect_success 'interaction with submodules' '
                git commit -m "add submodule" &&
                git sparse-checkout init --cone &&
                git sparse-checkout set folder1
-       ) &&
+       )
+'
+
+test_expect_success 'interaction with submodules' '
        check_files super a folder1 modules &&
        check_files super/modules/child a deep folder1 folder2
 '
 
+test_expect_success 'check-rules interaction with submodules' '
+       git -C super ls-tree --name-only -r HEAD >all-files &&
+       git -C super sparse-checkout check-rules >check-rules-matches <all-files &&
+
+       test_i18ngrep ! "modules/" check-rules-matches &&
+       test_i18ngrep "folder1/" check-rules-matches
+'
+
 test_expect_success 'different sparse-checkouts with worktrees' '
        git -C repo sparse-checkout set --cone deep folder1 &&
        git -C repo worktree add --detach ../worktree &&
@@ -882,4 +893,156 @@ test_expect_success 'by default, non-cone mode will warn on individual files' '
        grep "pass a leading slash before paths.*if you want a single file" warning
 '
 
+test_expect_success 'setup bare repo' '
+       git clone --bare "file://$(pwd)/repo" bare
+'
+test_expect_success 'list fails outside work tree' '
+       test_must_fail git -C bare sparse-checkout list 2>err &&
+       test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'add fails outside work tree' '
+       test_must_fail git -C bare sparse-checkout add deeper 2>err &&
+       test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'set fails outside work tree' '
+       test_must_fail git -C bare sparse-checkout set deeper 2>err &&
+       test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'init fails outside work tree' '
+       test_must_fail git -C bare sparse-checkout init 2>err &&
+       test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'reapply fails outside work tree' '
+       test_must_fail git -C bare sparse-checkout reapply 2>err &&
+       test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'disable fails outside work tree' '
+       test_must_fail git -C bare sparse-checkout disable 2>err &&
+       test_i18ngrep "this operation must be run in a work tree" err
+'
+
+test_expect_success 'setup clean' '
+       git -C repo clean -fdx
+'
+
+test_expect_success 'check-rules cone mode' '
+       cat >rules <<-\EOF &&
+       folder1
+       deep/deeper1/deepest
+       EOF
+
+       git -C bare ls-tree -r --name-only HEAD >all-files &&
+       git -C bare sparse-checkout check-rules --cone \
+               --rules-file ../rules >check-rules-file <all-files &&
+
+       git -C repo sparse-checkout set --cone --stdin <rules&&
+       git -C repo ls-files -t >out &&
+       sed -n "/^S /!s/^. //p" out >ls-files &&
+
+       git -C repo sparse-checkout check-rules >check-rules-default <all-files &&
+
+       test_i18ngrep "deep/deeper1/deepest/a" check-rules-file &&
+       test_i18ngrep ! "deep/deeper2" check-rules-file &&
+
+       test_cmp check-rules-file ls-files &&
+       test_cmp check-rules-file check-rules-default
+'
+
+test_expect_success 'check-rules non-cone mode' '
+       cat >rules <<-\EOF &&
+       deep/deeper1/deepest/a
+       EOF
+
+       git -C bare ls-tree -r --name-only HEAD >all-files &&
+       git -C bare sparse-checkout check-rules --no-cone --rules-file ../rules\
+               >check-rules-file <all-files &&
+
+       cat rules | git -C repo sparse-checkout set --no-cone --stdin &&
+       git -C repo ls-files -t >out &&
+       sed -n "/^S /!s/^. //p" out >ls-files &&
+
+       git -C repo sparse-checkout check-rules >check-rules-default <all-files &&
+
+       cat >expect <<-\EOF &&
+       deep/deeper1/deepest/a
+       EOF
+
+       test_cmp expect check-rules-file &&
+       test_cmp check-rules-file ls-files &&
+       test_cmp check-rules-file check-rules-default
+'
+
+test_expect_success 'check-rules cone mode is default' '
+       cat >rules <<-\EOF &&
+       folder1
+       EOF
+
+       cat >all-files <<-\EOF &&
+       toplevel
+       folder2/file
+       folder1/file
+       EOF
+
+       cat >expect <<-\EOF &&
+       toplevel
+       folder1/file
+       EOF
+
+       git -C repo sparse-checkout set --no-cone &&
+       git -C repo sparse-checkout check-rules \
+               --rules-file ../rules >actual <all-files &&
+
+       git -C bare sparse-checkout check-rules \
+               --rules-file ../rules >actual-bare <all-files &&
+
+       test_cmp expect actual &&
+       test_cmp expect actual-bare
+'
+
+test_expect_success 'check-rules quoting' '
+       cat >rules <<-EOF &&
+       "folder\" a"
+       EOF
+       cat >files <<-EOF &&
+       "folder\" a/file"
+       "folder\" b/file"
+       EOF
+       cat >expect <<-EOF &&
+       "folder\" a/file"
+       EOF
+       git sparse-checkout check-rules --cone \
+               --rules-file rules >actual <files &&
+
+       test_cmp expect actual
+'
+
+test_expect_success 'check-rules null termination' '
+       cat >rules <<-EOF &&
+       "folder\" a"
+       EOF
+
+       lf_to_nul >files <<-EOF &&
+       folder" a/a
+       folder" a/b
+       folder" b/fileQ
+       EOF
+
+       cat >expect <<-EOF &&
+       folder" a/aQfolder" a/bQ
+       EOF
+
+       git sparse-checkout check-rules --cone -z \
+               --rules-file rules >actual.nul <files &&
+       nul_to_q <actual.nul >actual &&
+       echo >>actual &&
+
+       test_cmp expect actual
+'
+
+
 test_done
index 801919009e1d073735ac785a49b0aa353e565c55..8a95adf4b50de6b543598ceac84f8515d9442f4d 100755 (executable)
@@ -1377,7 +1377,7 @@ test_expect_success 'index.sparse disabled inline uses full index' '
        ! test_region index ensure_full_index trace2.txt
 '
 
-ensure_not_expanded () {
+run_sparse_index_trace2 () {
        rm -f trace2.txt &&
        if test -z "$WITHOUT_UNTRACKED_TXT"
        then
@@ -1397,7 +1397,16 @@ ensure_not_expanded () {
                        git -C sparse-index "$@" \
                        >sparse-index-out \
                        2>sparse-index-error || return 1
-       fi &&
+       fi
+}
+
+ensure_expanded () {
+       run_sparse_index_trace2 "$@" &&
+       test_region index ensure_full_index trace2.txt
+}
+
+ensure_not_expanded () {
+       run_sparse_index_trace2 "$@" &&
        test_region ! index ensure_full_index trace2.txt
 }
 
@@ -1514,6 +1523,31 @@ test_expect_success 'sparse-index is not expanded: stash' '
        ensure_not_expanded stash pop
 '
 
+test_expect_success 'describe tested on all' '
+       init_repos &&
+
+       # Add tag to be read by describe
+
+       run_on_all git tag -a v1.0 -m "Version 1" &&
+       test_all_match git describe --dirty &&
+       run_on_all rm g &&
+       test_all_match git describe --dirty
+'
+
+
+test_expect_success 'sparse-index is not expanded: describe' '
+       init_repos &&
+
+       # Add tag to be read by describe
+
+       git -C sparse-index tag -a v1.0 -m "Version 1" &&
+
+       ensure_not_expanded describe --dirty &&
+       echo "test" >>sparse-index/g &&
+       ensure_not_expanded describe --dirty &&
+       ensure_not_expanded describe
+'
+
 test_expect_success 'sparse index is not expanded: diff' '
        init_repos &&
 
@@ -2055,4 +2089,174 @@ test_expect_success 'grep sparse directory within submodules' '
        test_cmp actual expect
 '
 
+test_expect_success 'write-tree' '
+       init_repos &&
+
+       test_all_match git write-tree &&
+
+       write_script edit-contents <<-\EOF &&
+       echo text >>"$1"
+       EOF
+
+       # make a change inside the sparse cone
+       run_on_all ../edit-contents deep/a &&
+       test_all_match git update-index deep/a &&
+       test_all_match git write-tree &&
+       test_all_match git status --porcelain=v2 &&
+
+       # make a change outside the sparse cone
+       run_on_all mkdir -p folder1 &&
+       run_on_all cp a folder1/a &&
+       run_on_all ../edit-contents folder1/a &&
+       test_all_match git update-index folder1/a &&
+       test_all_match git write-tree &&
+       test_all_match git status --porcelain=v2 &&
+
+       # check that SKIP_WORKTREE files are not materialized
+       test_path_is_missing sparse-checkout/folder2/a &&
+       test_path_is_missing sparse-index/folder2/a
+'
+
+test_expect_success 'sparse-index is not expanded: write-tree' '
+       init_repos &&
+
+       ensure_not_expanded write-tree &&
+
+       echo "test1" >>sparse-index/a &&
+       git -C sparse-index update-index a &&
+       ensure_not_expanded write-tree
+'
+
+test_expect_success 'diff-files with pathspec inside sparse definition' '
+       init_repos &&
+
+       write_script edit-contents <<-\EOF &&
+       echo text >>"$1"
+       EOF
+
+       run_on_all ../edit-contents deep/a &&
+
+       test_all_match git diff-files &&
+
+       test_all_match git diff-files -- deep/a &&
+
+       # test wildcard
+       test_all_match git diff-files -- "deep/*"
+'
+
+test_expect_success 'diff-files with pathspec outside sparse definition' '
+       init_repos &&
+
+       test_sparse_match git diff-files -- folder2/a &&
+
+       write_script edit-contents <<-\EOF &&
+       echo text >>"$1"
+       EOF
+
+       # The directory "folder1" is outside the cone of interest
+       # and will not exist in the sparse checkout repositories.
+       # Create it as needed, add file "folder1/a" there with
+       # contents that is different from the staged version.
+       run_on_all mkdir -p folder1 &&
+       run_on_all cp a folder1/a &&
+
+       run_on_all ../edit-contents folder1/a &&
+       test_all_match git diff-files &&
+       test_all_match git diff-files -- folder1/a &&
+       test_all_match git diff-files -- "folder*/a"
+'
+
+test_expect_success 'sparse index is not expanded: diff-files' '
+       init_repos &&
+
+       write_script edit-contents <<-\EOF &&
+       echo text >>"$1"
+       EOF
+
+       run_on_all ../edit-contents deep/a &&
+
+       ensure_not_expanded diff-files &&
+       ensure_not_expanded diff-files -- deep/a &&
+       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_done
index f1d42b62b0585cbca3e4c494bf01142d5f1ffdb7..387d336c91f44e58d1e5073febdae266156212c8 100755 (executable)
@@ -98,6 +98,23 @@ test_expect_success 'subsections are not canonicalized by git-config' '
        test_cmp_config two section.SubSection.key
 '
 
+test_missing_key () {
+       local key="$1" &&
+       local title="$2" &&
+       test_expect_success "value for $title is not printed" '
+               test_must_fail git config "$key" >out 2>err &&
+               test_must_be_empty out &&
+               test_must_be_empty err
+       '
+}
+
+test_missing_key 'missingsection.missingkey' 'missing section and missing key'
+test_missing_key 'missingsection.penguin' 'missing section and existing key'
+test_missing_key 'section.missingkey' 'existing section and missing key'
+test_missing_key 'section.MissingSubSection.missingkey' 'missing subsection and missing key'
+test_missing_key 'section.SubSection.missingkey' 'existing subsection and missing key'
+test_missing_key 'section.MissingSubSection.key' 'missing subsection and existing key'
+
 cat > .git/config <<\EOF
 [alpha]
 bar = foo
@@ -1488,35 +1505,29 @@ test_expect_success 'git config ignores pairs without count' '
        test_must_be_empty error
 '
 
-test_expect_success 'git config ignores pairs with zero count' '
-       test_must_fail env \
-               GIT_CONFIG_COUNT=0 \
-               GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
-               git config pair.one
-'
-
 test_expect_success 'git config ignores pairs exceeding count' '
        GIT_CONFIG_COUNT=1 \
                GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
                GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \
-               git config --get-regexp "pair.*" >actual &&
+               git config --get-regexp "pair.*" >actual 2>error &&
        cat >expect <<-EOF &&
        pair.one value
        EOF
-       test_cmp expect actual
+       test_cmp expect actual &&
+       test_must_be_empty error
 '
 
 test_expect_success 'git config ignores pairs with zero count' '
        test_must_fail env \
                GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
-               git config pair.one >error &&
+               git config pair.one 2>error &&
        test_must_be_empty error
 '
 
 test_expect_success 'git config ignores pairs with empty count' '
        test_must_fail env \
                GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
-               git config pair.one >error &&
+               git config pair.one 2>error &&
        test_must_be_empty error
 '
 
@@ -1601,11 +1612,11 @@ test_expect_success 'git config --edit respects core.editor' '
 # malformed configuration files
 test_expect_success 'barf on syntax error' '
        cat >.git/config <<-\EOF &&
-       # broken section line
+       # broken key=value
        [section]
        key garbage
        EOF
-       test_must_fail git config --get section.key >actual 2>error &&
+       test_must_fail git config --get section.key 2>error &&
        test_i18ngrep " line 3 " error
 '
 
@@ -1615,17 +1626,17 @@ test_expect_success 'barf on incomplete section header' '
        [section
        key = value
        EOF
-       test_must_fail git config --get section.key >actual 2>error &&
+       test_must_fail git config --get section.key 2>error &&
        test_i18ngrep " line 2 " error
 '
 
 test_expect_success 'barf on incomplete string' '
        cat >.git/config <<-\EOF &&
-       # broken section line
+       # broken value string
        [section]
        key = "value string
        EOF
-       test_must_fail git config --get section.key >actual 2>error &&
+       test_must_fail git config --get section.key 2>error &&
        test_i18ngrep " line 3 " error
 '
 
@@ -1657,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/"]
@@ -2044,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
@@ -2112,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 1b6437ec0794e887e1d14452c516c487d0bb007f..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 &&
@@ -89,7 +111,7 @@ do
                rm -f .git/info/refs &&
                git update-server-info &&
                actual="$(test_modebits .git/info/refs)" &&
-               verbose test "x$actual" = "x-$y"
+               test "x$actual" = "x-$y"
 
        '
 
@@ -99,7 +121,7 @@ do
                rm -f .git/info/refs &&
                git update-server-info &&
                actual="$(test_modebits .git/info/refs)" &&
-               verbose test "x$actual" = "x-$x"
+               test "x$actual" = "x-$x"
 
        '
 
index 70389fa2ebbfa47ad410ca5c30bb294b6cf0753f..179474fa651e159bf68714620ab4f1be2c259fe5 100755 (executable)
@@ -37,7 +37,7 @@ test_expect_success 'gitdir selection on normal repos' '
 
 test_expect_success 'gitdir selection on unsupported repo' '
        # Make sure it would stop at test2, not trash
-       test_expect_code 1 git -C test2 config core.repositoryformatversion >actual
+       test_expect_code 1 git -C test2 config core.repositoryformatversion
 '
 
 test_expect_success 'gitdir not required mode' '
index b38e158d3b212a0157f5d0f862103713c6a39e57..777648722c72830c86d27f7083fac78843844ca0 100755 (executable)
@@ -58,6 +58,8 @@ test_expect_success 'setup default config' '
                skin = false
                nose = 1
                horns
+       [value]
+               less
        EOF
 '
 
@@ -116,10 +118,53 @@ test_expect_success 'find value with the highest priority' '
        check_config get_value case.baz "hask"
 '
 
+test_expect_success 'return value for an existing key' '
+       test-tool config get lamb.chop >out 2>err &&
+       test_must_be_empty out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'return value for value-less key' '
+       test-tool config get value.less >out 2>err &&
+       test_must_be_empty out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'return value for a missing key' '
+       cat >expect <<-\EOF &&
+       Value not found for "missing.key"
+       EOF
+       test_expect_code 1 test-tool config get missing.key >actual 2>err &&
+       test_cmp actual expect &&
+       test_must_be_empty err
+'
+
+test_expect_success 'return value for a bad key: CONFIG_INVALID_KEY' '
+       cat >expect <<-\EOF &&
+       Key "fails.iskeychar.-" is invalid
+       EOF
+       test_expect_code 1 test-tool config get fails.iskeychar.- >actual 2>err &&
+       test_cmp actual expect &&
+       test_must_be_empty out
+'
+
+test_expect_success 'return value for a bad key: CONFIG_NO_SECTION_OR_NAME' '
+       cat >expect <<-\EOF &&
+       Key "keynosection" has no section
+       EOF
+       test_expect_code 1 test-tool config get keynosection >actual 2>err &&
+       test_cmp actual expect &&
+       test_must_be_empty out
+'
+
 test_expect_success 'find integer value for a key' '
        check_config get_int lamb.chop 65
 '
 
+test_expect_success 'parse integer value during iteration' '
+       check_config git_config_int lamb.chop 65
+'
+
 test_expect_success 'find string value for a key' '
        check_config get_string case.baz hask &&
        check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\""
@@ -134,6 +179,11 @@ test_expect_success 'find integer if value is non parse-able' '
        check_config expect_code 128 get_int lamb.head
 '
 
+test_expect_success 'non parse-able integer value during iteration' '
+       check_config expect_code 128 git_config_int lamb.head 2>result &&
+       grep "fatal: bad numeric config value .* in file \.git/config" result
+'
+
 test_expect_success 'find bool value for the entered key' '
        check_config get_bool goat.head 1 &&
        check_config get_bool goat.skin 0 &&
@@ -146,6 +196,71 @@ test_expect_success 'find multiple values' '
        check_config get_value_multi case.baz sam bat hask
 '
 
+test_NULL_in_multi () {
+       local op="$1" &&
+       local file="$2" &&
+
+       test_expect_success "$op: NULL value in config${file:+ in $file}" '
+               config="$file" &&
+               if test -z "$config"
+               then
+                       config=.git/config &&
+                       test_when_finished "mv $config.old $config" &&
+                       mv "$config" "$config".old
+               fi &&
+
+               # Value-less in the middle of a list
+               cat >"$config" <<-\EOF &&
+               [a]key=x
+               [a]key
+               [a]key=y
+               EOF
+               case "$op" in
+               *_multi)
+                       cat >expect <<-\EOF
+                       x
+                       (NULL)
+                       y
+                       EOF
+                       ;;
+               *)
+                       cat >expect <<-\EOF
+                       y
+                       EOF
+                       ;;
+               esac &&
+               test-tool config "$op" a.key $file >actual &&
+               test_cmp expect actual &&
+
+               # Value-less at the end of a least
+               cat >"$config" <<-\EOF &&
+               [a]key=x
+               [a]key=y
+               [a]key
+               EOF
+               case "$op" in
+               *_multi)
+                       cat >expect <<-\EOF
+                       x
+                       y
+                       (NULL)
+                       EOF
+                       ;;
+               *)
+                       cat >expect <<-\EOF
+                       (NULL)
+                       EOF
+                       ;;
+               esac &&
+               test-tool config "$op" a.key $file >actual &&
+               test_cmp expect actual
+       '
+}
+
+test_NULL_in_multi "get_value_multi"
+test_NULL_in_multi "configset_get_value" "my.config"
+test_NULL_in_multi "configset_get_value_multi" "my.config"
+
 test_expect_success 'find value from a configset' '
        cat >config2 <<-\EOF &&
        [case]
@@ -207,7 +322,7 @@ test_expect_success 'proper error on error in default config files' '
        cp .git/config .git/config.old &&
        test_when_finished "mv .git/config.old .git/config" &&
        echo "[" >>.git/config &&
-       echo "fatal: bad config line 34 in file .git/config" >expect &&
+       echo "fatal: bad config line 36 in file .git/config" >expect &&
        test_expect_code 128 test-tool config get_value foo.bar 2>actual &&
        test_cmp expect actual
 '
index cf58cf025cd2af621f6d58cdaf02d3be0480190c..4d66cd7f4a1fce8ebdaa42a37e7bd8f03853645e 100755 (executable)
@@ -1568,6 +1568,7 @@ test_expect_success 'transaction can create and delete' '
        EOF
        git update-ref --stdin <stdin >actual &&
        printf "%s: ok\n" start commit start commit >expect &&
+       test_cmp expect actual &&
        test_must_fail git show-ref --verify refs/heads/create-and-delete
 '
 
@@ -1595,6 +1596,8 @@ test_expect_success 'transaction cannot restart ongoing transaction' '
        commit
        EOF
        test_must_fail git update-ref --stdin <stdin >actual &&
+       printf "%s: ok\n" start >expect &&
+       test_cmp expect actual &&
        test_must_fail git show-ref --verify refs/heads/restart
 '
 
index be23be30c768304d35d79cf6905d576293125801..c7745e1bf69e910c2d66a61bb8bef36b45473a56 100755 (executable)
@@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
 reset_to_sane
 
 test_expect_success 'symbolic-ref refuses bare sha1' '
-       test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)
+       rev=$(git rev-parse HEAD) &&
+       test_must_fail git symbolic-ref HEAD "$rev"
 '
 
 reset_to_sane
index b5606d93b52bf44366a51f3d4b6dd19e7a8816ab..937ae0d73347c3d0797fd28b5c3bfa83baf55632 100755 (executable)
@@ -551,7 +551,6 @@ test_expect_success REFFILES 'no bogus intermediate values during delete' '
        git update-ref $prefix/foo $C &&
        git pack-refs --all &&
        git update-ref $prefix/foo $D &&
-       git for-each-ref $prefix >unchanged &&
        # Now try to update the reference, but hold the `packed-refs` lock
        # for a while to see what happens while the process is blocked:
        : >.git/packed-refs.lock &&
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 fdb886dfe431f36dfc4ef6bcf24abf6827c2243d..5805d47eb96c1eb72c761e50a8ba4670f5d7947a 100755 (executable)
@@ -989,10 +989,7 @@ test_expect_success 'fsck error and recovery on invalid object type' '
 
                garbage_blob=$(git hash-object --stdin -w -t garbage --literally </dev/null) &&
 
-               cat >err.expect <<-\EOF &&
-               fatal: invalid object type
-               EOF
-               test_must_fail git fsck >out 2>err &&
+               test_must_fail git fsck 2>err &&
                grep -e "^error" -e "^fatal" err >errors &&
                test_line_count = 1 errors &&
                grep "$garbage_blob: object is of unknown type '"'"'garbage'"'"':" err
@@ -1023,4 +1020,34 @@ test_expect_success 'fsck error on gitattributes with excessive size' '
        test_cmp expected actual
 '
 
+test_expect_success 'fsck detects problems in worktree index' '
+       test_when_finished "git worktree remove -f wt" &&
+       git worktree add wt &&
+
+       echo "this will be removed to break the worktree index" >wt/file &&
+       git -C wt add file &&
+       blob=$(git -C wt rev-parse :file) &&
+       remove_object $blob &&
+
+       test_must_fail git fsck --name-objects >actual 2>&1 &&
+       cat >expect <<-EOF &&
+       missing blob $blob (.git/worktrees/wt/index:file)
+       EOF
+       test_cmp expect actual
+'
+
+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 current worktree index" >file &&
+       git add file &&
+       blob=$(git rev-parse :file) &&
+       remove_object $blob &&
+
+       test_must_fail git fsck --name-objects >actual 2>&1 &&
+       cat >expect <<-EOF &&
+       missing blob $blob (:file)
+       EOF
+       test_cmp expect actual
+'
+
 test_done
index de1d48f3ba29116d073b0a5573a2031fae7fcc1d..dd811b7fb467c4f3f27ef1be14427e022f73caeb 100755 (executable)
@@ -302,14 +302,14 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
        |EOF
        END_EXPECT
 
-       test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+       test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'test --parseopt invalid opt-spec' '
        test_write_lines x -- "=, x" >spec &&
        echo "fatal: missing opt-spec before option flags" >expect &&
-       test_must_fail git rev-parse --parseopt -- >out <spec 2>err &&
+       test_must_fail git rev-parse --parseopt -- <spec 2>err &&
        test_cmp expect err
 '
 
@@ -339,7 +339,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
        |EOF
        END_EXPECT
 
-       test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+       test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
        test_cmp expect actual
 '
 
index 0fafcf9dde385f2c2bac7fbd846098908a72f09b..c1679e31d8afca409323484d588bf63b264f45f2 100755 (executable)
@@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_prefix() {
-       test_expect_success "$1" \
-       "test '$2' = \"\$(git rev-parse --show-prefix)\""
+       local expect="$2" &&
+       test_expect_success "$1: git rev-parse --show-prefix is '$2'" '
+               echo "$expect" >expect &&
+               git rev-parse --show-prefix >actual &&
+               test_cmp expect actual
+       '
 }
 
 test_fail() {
index c34714ffe3fbe5545da1d05b9a74cfc6113e43dd..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
 
 
@@ -97,7 +98,8 @@ test_expect_success 'my-side@{u} resolves to correct commit' '
        commit_subject my-side >actual &&
        test_cmp expect actual &&
        echo 5 >expect &&
-       commit_subject my-side@{u} >actual
+       commit_subject my-side@{u} >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'not-tracking@{u} fails' '
@@ -183,6 +185,11 @@ test_expect_success '@{u} error message when no upstream' '
        test_cmp expect actual
 '
 
+test_expect_success '@{u} silent error when no upstream' '
+       test_must_fail git rev-parse --verify --quiet @{u} 2>actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'branch@{u} error message with misspelt branch' '
        cat >expect <<-EOF &&
        fatal: no such branch: ${SQ}no-such-branch${SQ}
@@ -258,7 +265,8 @@ test_expect_success '@{reflog}-parsing does not look beyond colon' '
        git add @{yesterday} &&
        git commit -m "funny reflog file" &&
        git hash-object @{yesterday} >expect &&
-       git rev-parse HEAD:@{yesterday} >actual
+       git rev-parse HEAD:@{yesterday} >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success '@{upstream}-parsing does not look beyond colon' '
@@ -266,7 +274,8 @@ test_expect_success '@{upstream}-parsing does not look beyond colon' '
        git add @{upstream} &&
        git commit -m "funny upstream file" &&
        git hash-object @{upstream} >expect &&
-       git rev-parse HEAD:@{upstream} >actual
+       git rev-parse HEAD:@{upstream} >actual &&
+       test_cmp expect actual
 '
 
 test_done
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 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 112682a45a1df3d5c19eab03ec79c1202d2cab71..67d18cfa104b867bfdd2004df0bc8c9e305cfdc9 100755 (executable)
@@ -22,8 +22,10 @@ test_expect_success \
 git checkout-index symlink &&
 test -f symlink'
 
-test_expect_success \
-'the file must be the blob we added during the setup' '
-test "$(git hash-object -t blob symlink)" = $l'
+test_expect_success 'the file must be the blob we added during the setup' '
+       echo "$l" >expect &&
+       git hash-object -t blob symlink >actual &&
+       test_cmp expect actual
+'
 
 test_done
index 2c8c926b4d73a32a23380ec347e6c89c5a8e9657..95405886640a4fb304a565ccc4a166f450c0f5c8 100755 (executable)
@@ -16,7 +16,7 @@ test_expect_success 'setup ambiguous refs' '
 '
 
 test_expect_success 'checkout ambiguous ref succeeds' '
-       git checkout ambiguity >stdout 2>stderr
+       git checkout ambiguity 2>stderr
 '
 
 test_expect_success 'checkout produces ambiguity warning' '
@@ -37,7 +37,7 @@ test_expect_success 'checkout reports switch to branch' '
 '
 
 test_expect_success 'checkout vague ref succeeds' '
-       git checkout vagueness >stdout 2>stderr &&
+       git checkout vagueness 2>stderr &&
        test_set_prereq VAGUENESS_SUCCESS
 '
 
index 713c3fa6038632bff43ef8344be2d4a6a73cb32e..ecfacf0f7f3a5fa7c03fa837891c745dec10dda6 100755 (executable)
@@ -50,10 +50,13 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' '
 
 test_expect_success SYMLINKS 'the symlink remained' '
 
-       test_when_finished "rm a/b" &&
        test -h a/b
 '
 
+test_expect_success 'cleanup after previous symlink tests' '
+       rm a/b
+'
+
 test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing entries' '
        git checkout -f start &&
        mkdir dir &&
@@ -66,4 +69,15 @@ test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing
        test_path_is_file untracked/f
 '
 
+test_expect_success 'checkout --overwrite-ignore should succeed if only ignored files in the way' '
+       git checkout -b df_conflict &&
+       test_commit contents some_dir &&
+       git checkout start &&
+       mkdir some_dir &&
+       echo autogenerated information >some_dir/ignore &&
+       echo ignore >.git/info/exclude &&
+       git checkout --overwrite-ignore df_conflict &&
+       test_path_is_file some_dir
+'
+
 test_done
index 4a1c9014567542d2cc33425e3455defe708570a8..74049a9812ba4ff80bce1b235d636782800a5a13 100755 (executable)
@@ -305,10 +305,13 @@ test_expect_success 'loosely defined local base branch is reported correctly' '
        test_config branch.strict.merge refs/heads/main &&
        test_config branch.loose.merge main &&
 
-       git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
+       git checkout strict >expect.raw 2>&1 &&
+       sed -e "s/strict/BRANCHNAME/g" <expect.raw >expect &&
        status_uno_is_clean &&
-       git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
+       git checkout loose >actual.raw 2>&1 &&
+       sed -e "s/loose/BRANCHNAME/g" <actual.raw >actual &&
        status_uno_is_clean &&
+       grep BRANCHNAME actual &&
 
        test_cmp expect 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 5a7caf958c346620f6daffcc78ceaa75e03afe8f..e247a4735bbc26b01fecd600ed3e529bea16f464 100755 (executable)
@@ -146,4 +146,33 @@ test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
        test_cmp_config "" --default "" branch.main2.merge
 '
 
+test_expect_success 'switch back when temporarily detached and checked out elsewhere ' '
+       test_when_finished "
+               git worktree remove wt1 ||:
+               git worktree remove wt2 ||:
+               git checkout - ||:
+               git branch -D shared ||:
+       " &&
+       git checkout -b shared &&
+       test_commit shared-first &&
+       HASH1=$(git rev-parse --verify HEAD) &&
+       test_commit shared-second &&
+       test_commit shared-third &&
+       HASH2=$(git rev-parse --verify HEAD) &&
+       git worktree add wt1 -f shared &&
+       git -C wt1 bisect start &&
+       git -C wt1 bisect good $HASH1 &&
+       git -C wt1 bisect bad $HASH2 &&
+       git worktree add wt2 -f shared &&
+       git -C wt2 bisect start &&
+       git -C wt2 bisect good $HASH1 &&
+       git -C wt2 bisect bad $HASH2 &&
+       # we test in both worktrees to ensure that works
+       # as expected with "first" and "next" worktrees
+       test_must_fail git -C wt1 switch shared &&
+       git -C wt1 switch --ignore-other-worktrees shared &&
+       test_must_fail git -C wt2 switch shared &&
+       git -C wt2 switch --ignore-other-worktrees shared
+'
+
 test_done
index 7c43ddf1d99714ac5744b37dfb1badb6e0c785fc..c5d19dd973d7f4ea7a3a496d7df92a5c74fa667d 100755 (executable)
@@ -137,4 +137,20 @@ 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' '
+       for opts in \
+               "--staged --ours" \
+               "--staged --theirs" \
+               "--staged --merge" \
+               "--staged --conflict=diff3" \
+               "--staged --worktree --ours" \
+               "--staged --worktree --theirs" \
+               "--staged --worktree --merge" \
+               "--staged --worktree --conflict=zdiff3"
+       do
+               test_must_fail git restore $opts . 2>err &&
+               grep "cannot be used with --staged" err || return
+       done
+'
+
 test_done
index 07e6de84e6d090eeaa58dda7176986b28b3bc18e..89b285fa3a608f917a269c56ee2f44fa51f5d01f 100755 (executable)
@@ -83,7 +83,7 @@ test_expect_success '.lock files cleaned up' '
        cd repo &&
        git config core.worktree ../../worktree &&
        # --refresh triggers late setup_work_tree,
-       # active_cache_changed is zero, rollback_lock_file fails
+       # the_index.cache_changed is zero, rollback_lock_file fails
        git update-index --refresh --verbose >out &&
        test_must_be_empty out &&
        ! test -f .git/index.lock
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..051363acbbc784ec5b2cc3d0c6ddfc3af87cdd6c 100755 (executable)
@@ -298,17 +298,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 +333,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 +554,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 +644,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 +705,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..469443d8ae8c44483c7dbea8dd3c3fc2baef0745 100755 (executable)
@@ -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 efb7450bf1e9c14fc5563564b5b4e6913bd7c97c..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 &&
@@ -54,6 +89,22 @@ test_expect_success 'git ls-files --format path v.s. -s' '
        test_cmp expect actual
 '
 
+test_expect_success 'git ls-files --format with relative path' '
+       cat >expect <<-\EOF &&
+       ../o1.txt
+       ../o2.txt
+       ../o3.txt
+       ../o4.txt
+       ../o5.txt
+       ../o6.txt
+       EOF
+       mkdir sub &&
+       cd sub &&
+       git ls-files --format="%(path)" ":/" >../actual &&
+       cd .. &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git ls-files --format with -m' '
        echo change >o1.txt &&
        cat >expect <<-\EOF &&
index c4a72ae44623a0bab3ce06c1a5e850e9e8405054..5a06732ca730f4a4becff478cc96f20b8931f6fc 100755 (executable)
@@ -40,7 +40,7 @@ test_expect_success 'setup' '
        git commit -a -m "remove them all" &&
 
        # The bug also requires some entry before our directory so that
-       # prune_path will modify the_index.cache
+       # prune_index will modify the_repository->index.cache
 
        mkdir a_directory_that_sorts_before_sub &&
        >a_directory_that_sorts_before_sub/file &&
@@ -56,7 +56,7 @@ test_expect_success 'usage' '
 '
 
 test_expect_success 'git ls-files --with-tree should succeed from subdir' '
-       # We have to run from a sub-directory to trigger prune_path
+       # We have to run from a sub-directory to trigger prune_index
        # Then we finally get to run our --with-tree test
        (
                cd sub &&
index 5d871fde960a032bbf5523dc2fee578745d1479d..4dd42df38c25615e0833b754d1a2c3132ef0bf1d 100755 (executable)
@@ -431,4 +431,15 @@ match 1 1 1 1 'a' '[B-a]'
 match 0 1 0 1 'z' '[Z-y]'
 match 1 1 1 1 'Z' '[Z-y]'
 
+test_expect_success 'matching does not exhibit exponential behavior' '
+       {
+               test-tool wildmatch wildmatch \
+                       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab \
+                       "*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a" &
+               pid=$!
+       } &&
+       sleep 2 &&
+       ! kill $!
+'
+
 test_done
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 5a169b68d6af4d3db62e88dcdc4fb765ee5232a6..daf1666df7adb9594c50445764440ad339f43645 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
 
@@ -239,15 +240,34 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
        git worktree prune
 '
 
+test_expect_success 'git branch -M fails if updating any linked working tree fails' '
+       git worktree add -b baz bazdir1 &&
+       git worktree add -f bazdir2 baz &&
+       touch .git/worktrees/bazdir1/HEAD.lock &&
+       test_must_fail git branch -M baz bam &&
+       test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&
+       git branch -M bam baz &&
+       rm .git/worktrees/bazdir1/HEAD.lock &&
+       touch .git/worktrees/bazdir2/HEAD.lock &&
+       test_must_fail git branch -M baz bam &&
+       test $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam &&
+       rm -rf bazdir1 bazdir2 &&
+       git worktree prune
+'
+
 test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '
        git checkout -b baz &&
        git worktree add -f bazdir baz &&
        (
                cd bazdir &&
                git branch -M baz bam &&
-               test $(git rev-parse --abbrev-ref HEAD) = bam
+               echo bam >expect &&
+               git rev-parse --abbrev-ref HEAD >actual &&
+               test_cmp expect actual
        ) &&
-       test $(git rev-parse --abbrev-ref HEAD) = bam &&
+       echo bam >expect &&
+       git rev-parse --abbrev-ref HEAD >actual &&
+       test_cmp expect actual &&
        rm -r bazdir &&
        git worktree prune
 '
@@ -279,6 +299,20 @@ test_expect_success 'git branch -M and -C fail on detached HEAD' '
        test_cmp expect err
 '
 
+test_expect_success 'git branch -m should work with orphan branches' '
+       test_when_finished git checkout - &&
+       test_when_finished git worktree remove -f wt &&
+       git worktree add wt --detach &&
+       # rename orphan in another worktreee
+       git -C wt checkout --orphan orphan-foo-wt &&
+       git branch -m orphan-foo-wt orphan-bar-wt &&
+       test orphan-bar-wt=$(git -C orphan-worktree branch --show-current) &&
+       # rename orphan in the current worktree
+       git checkout --orphan orphan-foo &&
+       git branch -m orphan-foo orphan-bar &&
+       test orphan-bar=$(git branch --show-current)
+'
+
 test_expect_success 'git branch -d on orphan HEAD (merged)' '
        test_when_finished git checkout main &&
        git checkout --orphan orphan &&
index ea7cfd1951d8b2173c8fe13f1bc307ff9e7cfa1c..b17f388f56dfea819e70a04cf25000f0fb4b3658 100755 (executable)
@@ -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,6 +213,15 @@ 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'\'.'
@@ -221,4 +246,22 @@ test_expect_success 'fatal descriptions on non-existent branch' '
        test_cmp expect actual
 '
 
+test_expect_success 'error descriptions on orphan branch' '
+       test_when_finished git worktree remove -f wt &&
+       git worktree add wt --detach &&
+       git -C wt checkout --orphan 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_orphan_error -C wt branch $1 $2 &&                # implicit branch
+               test_orphan_error -C wt branch $1 orphan-branch $2 &&  # explicit branch
+               test_orphan_error branch $1 orphan-branch $2           # different worktree
+       } &&
+       test_branch_op_in_wt --edit-description &&
+       test_branch_op_in_wt --set-upstream-to=ne &&
+       test_branch_op_in_wt -c new-branch
+'
+
 test_done
index d34d77f89348d86518375a66e277bb118ff29c22..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
@@ -337,10 +353,48 @@ test_expect_success 'git branch --format option' '
        test_cmp expect actual
 '
 
+test_expect_success 'git branch --format with ahead-behind' '
+       cat >expect <<-\EOF &&
+       (HEAD detached from fromtag) 0 0
+       refs/heads/ambiguous 0 0
+       refs/heads/branch-one 1 0
+       refs/heads/branch-two 0 0
+       refs/heads/main 1 0
+       refs/heads/ref-to-branch 1 0
+       refs/heads/ref-to-remote 1 0
+       EOF
+       git branch --format="%(refname) %(ahead-behind:HEAD)" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git branch with --format=%(rest) must fail' '
        test_must_fail git branch --format="%(rest)" >actual
 '
 
+test_expect_success 'git branch --format --omit-empty' '
+       cat >expect <<-\EOF &&
+       Refname is (HEAD detached from fromtag)
+       Refname is refs/heads/ambiguous
+       Refname is refs/heads/branch-one
+       Refname is refs/heads/branch-two
+
+       Refname is refs/heads/ref-to-branch
+       Refname is refs/heads/ref-to-remote
+       EOF
+       git branch --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual &&
+       test_cmp expect actual &&
+       cat >expect <<-\EOF &&
+       Refname is (HEAD detached from fromtag)
+       Refname is refs/heads/ambiguous
+       Refname is refs/heads/branch-one
+       Refname is refs/heads/branch-two
+       Refname is refs/heads/ref-to-branch
+       Refname is refs/heads/ref-to-remote
+       EOF
+       git branch --omit-empty --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'worktree colors correct' '
        cat >expect <<-EOF &&
        * <GREEN>(HEAD detached from fromtag)<RESET>
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 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) &&
index 141d3e4ca4dc49181b31aff8a540a551ce8e4805..9bd5dbf341fd81a80dbebf0e1fafe623defecfa4 100755 (executable)
@@ -360,7 +360,12 @@ test_expect_success 'merge z into y with invalid strategy => Fail/No changes' '
 
 test_expect_success 'merge z into y with invalid configuration option => Fail/No changes' '
        git config core.notesRef refs/notes/y &&
-       test_must_fail git -c notes.mergeStrategy="foo" notes merge z &&
+       cat >expect <<-\EOF &&
+       error: unknown notes merge strategy foo
+       fatal: unable to parse '\''notes.mergeStrategy'\'' from command-line config
+       EOF
+       test_must_fail git -c notes.mergeStrategy="foo" notes merge z 2>actual &&
+       test_cmp expect actual &&
        # Verify no changes (y)
        verify_notes y y
 '
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 d5a8ee39fc478d3d3ab2ab71ec780efd76140d20..3ce918fdb8062fc5f720bb890ad58a2676547218 100755 (executable)
@@ -388,6 +388,20 @@ test_expect_success 'switch to branch checked out here' '
        git rebase main main
 '
 
+test_expect_success 'switch to branch checked out elsewhere fails' '
+       test_when_finished "
+               git worktree remove wt1 &&
+               git worktree remove wt2 &&
+               git branch -d shared
+       " &&
+       git worktree add wt1 -b shared &&
+       git worktree add wt2 -f shared &&
+       # we test in both worktrees to ensure that works
+       # as expected with "first" and "next" worktrees
+       test_must_fail git -C wt1 rebase shared shared &&
+       test_must_fail git -C wt2 rebase shared shared
+'
+
 test_expect_success 'switch to branch not checked out' '
        git checkout main &&
        git branch other &&
index 7e46f4ca850616b695cc6ffa061ca39ac404fb7d..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
@@ -131,27 +132,6 @@ test_expect_success 'picking rebase' '
        esac
 '
 
-test_expect_success 'rebase -s funny -Xopt' '
-       test_when_finished "rm -fr test-bin funny.was.run" &&
-       mkdir test-bin &&
-       cat >test-bin/git-merge-funny <<-EOF &&
-       #!$SHELL_PATH
-       case "\$1" in --opt) ;; *) exit 2 ;; esac
-       shift &&
-       >funny.was.run &&
-       exec git merge-recursive "\$@"
-       EOF
-       chmod +x test-bin/git-merge-funny &&
-       git reset --hard &&
-       git checkout -b test-funny main^ &&
-       test_commit funny &&
-       (
-               PATH=./test-bin:$PATH &&
-               git rebase -s funny -Xopt main
-       ) &&
-       test -f funny.was.run
-'
-
 test_expect_success 'rebase --skip works with two conflicts in a row' '
        git checkout second-side  &&
        tr "[A-Z]" "[a-z]" <newfile >tmp &&
index ff0afad63e2c5b1c03495046961eb27e2a593ed0..939fe8dfbc7fe2245765c296155ea8340c06ec9f 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' '
@@ -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 130e2f9b553003b9972ebe1010f17abff2d5ee05..c4e2fcac67e5886d47a392097dd14e2bd0141a73 100755 (executable)
@@ -62,61 +62,39 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
        rm -fr .git/rebase-* &&
        git reset --hard commit-new-file-F2-on-topic-branch &&
        test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
-       test_when_finished "rm -fr test-bin funny.was.run" &&
+       test_when_finished "rm -fr test-bin" &&
        mkdir test-bin &&
-       cat >test-bin/git-merge-funny <<-EOF &&
-       #!$SHELL_PATH
-       case "\$1" in --opt) ;; *) exit 2 ;; esac
-       shift &&
-       >funny.was.run &&
-       exec git merge-recursive "\$@"
+
+       write_script test-bin/git-merge-funny <<-\EOF &&
+       printf "[%s]\n" $# "$1" "$2" "$3" "$5" >actual
+       shift 3 &&
+       exec git merge-recursive "$@"
        EOF
-       chmod +x test-bin/git-merge-funny &&
-       (
-               PATH=./test-bin:$PATH &&
-               test_must_fail git rebase -s funny -Xopt main topic
-       ) &&
-       test -f funny.was.run &&
-       rm funny.was.run &&
-       echo "Resolved" >F2 &&
-       git add F2 &&
-       (
-               PATH=./test-bin:$PATH &&
-               git rebase --continue
-       ) &&
-       test -f funny.was.run
-'
 
-test_expect_success 'rebase -i --continue handles merge strategy and options' '
-       rm -fr .git/rebase-* &&
-       git reset --hard commit-new-file-F2-on-topic-branch &&
-       test_commit "commit-new-file-F3-on-topic-branch-for-dash-i" F3 32 &&
-       test_when_finished "rm -fr test-bin funny.was.run funny.args" &&
-       mkdir test-bin &&
-       cat >test-bin/git-merge-funny <<-EOF &&
-       #!$SHELL_PATH
-       echo "\$@" >>funny.args
-       case "\$1" in --opt) ;; *) exit 2 ;; esac
-       case "\$2" in --foo) ;; *) exit 2 ;; esac
-       case "\$4" in --) ;; *) exit 2 ;; esac
-       shift 2 &&
-       >funny.was.run &&
-       exec git merge-recursive "\$@"
+       cat >expect <<-\EOF &&
+       [7]
+       [--option=arg with space]
+       [--op"tion\]
+       [--new
+       line ]
+       [--]
        EOF
-       chmod +x test-bin/git-merge-funny &&
+
+       rm -f actual &&
        (
                PATH=./test-bin:$PATH &&
-               test_must_fail git rebase -i -s funny -Xopt -Xfoo main topic
+               test_must_fail git rebase -s funny -X"option=arg with space" \
+                               -Xop\"tion\\ -X"new${LF}line " main topic
        ) &&
-       test -f funny.was.run &&
-       rm funny.was.run &&
+       test_cmp expect actual &&
+       rm actual &&
        echo "Resolved" >F2 &&
        git add F2 &&
        (
                PATH=./test-bin:$PATH &&
                git rebase --continue
        ) &&
-       test -f funny.was.run
+       test_cmp expect actual
 '
 
 test_expect_success 'rebase -r passes merge strategy options correctly' '
@@ -137,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 &&
@@ -155,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' '
@@ -266,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 4711b37a28863e50a06e098bcbcd9417951c9b4d..2eba00bdf5898531744c8f77429a8f4d1ad1b91d 100755 (executable)
@@ -85,6 +85,11 @@ test_rebase_am_only () {
                test_must_fail git rebase $opt --reapply-cherry-picks A
        "
 
+       test_expect_success "$opt incompatible with --rebase-merges" "
+               git checkout B^0 &&
+               test_must_fail git rebase $opt --rebase-merges A
+       "
+
        test_expect_success "$opt incompatible with --update-refs" "
                git checkout B^0 &&
                test_must_fail git rebase $opt --update-refs A
@@ -101,6 +106,12 @@ test_rebase_am_only () {
                grep -e --no-autosquash err
        "
 
+       test_expect_success "$opt incompatible with rebase.rebaseMerges" "
+               git checkout B^0 &&
+               test_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err &&
+               grep -e --no-rebase-merges err
+       "
+
        test_expect_success "$opt incompatible with rebase.updateRefs" "
                git checkout B^0 &&
                test_must_fail git -c rebase.updateRefs=true rebase $opt A 2>err &&
@@ -113,6 +124,12 @@ test_rebase_am_only () {
                git -c rebase.autosquash=true rebase --no-autosquash $opt A
        "
 
+       test_expect_success "$opt okay with overridden rebase.rebaseMerges" "
+               test_when_finished \"git reset --hard B^0\" &&
+               git checkout B^0 &&
+               git -c rebase.rebaseMerges=true rebase --no-rebase-merges $opt A
+       "
+
        test_expect_success "$opt okay with overridden rebase.updateRefs" "
                test_when_finished \"git reset --hard B^0\" &&
                git checkout B^0 &&
index 48b76f82325da49d521bf4603566ebcbc3653ddc..1b3e97c8755f3d8b41549e70cf67529298118182 100755 (executable)
@@ -74,9 +74,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' '
        test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --onto files-main main &&
        : first pick results in no changes &&
        git rebase --skip &&
-       verbose test "$(commit_message HEAD~2)" = "topic_4" &&
-       verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
-       verbose test "$(commit_message HEAD)" = "Empty commit"
+       test "$(commit_message HEAD~2)" = "topic_4" &&
+       test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
+       test "$(commit_message HEAD)" = "Empty commit"
 '
 
 test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit' '
@@ -85,9 +85,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit'
        test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --rebase-merges --onto files-main --root &&
        : first pick results in no changes &&
        git rebase --skip &&
-       verbose test "$(commit_message HEAD~2)" = "topic_4" &&
-       verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
-       verbose test "$(commit_message HEAD)" = "Empty commit"
+       test "$(commit_message HEAD~2)" = "topic_4" &&
+       test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
+       test "$(commit_message HEAD)" = "Empty commit"
 '
 
 test_done
index fa2a06c19f0ff9890733817d066778c7634ab523..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 &&
@@ -250,6 +264,16 @@ test_expect_success 'with a branch tip that was cherry-picked already' '
        EOF
 '
 
+test_expect_success '--no-rebase-merges countermands --rebase-merges' '
+       git checkout -b no-rebase-merges E &&
+       git rebase --rebase-merges --no-rebase-merges C &&
+       test_cmp_graph C.. <<-\EOF
+       * B
+       * D
+       o C
+       EOF
+'
+
 test_expect_success 'do not rebase cousins unless asked for' '
        git checkout -b cousins main &&
        before="$(git rev-parse --verify HEAD)" &&
@@ -268,6 +292,40 @@ test_expect_success 'do not rebase cousins unless asked for' '
        EOF
 '
 
+test_expect_success 'rebase.rebaseMerges=rebase-cousins is equivalent to --rebase-merges=rebase-cousins' '
+       test_config rebase.rebaseMerges rebase-cousins &&
+       git checkout -b config-rebase-cousins main &&
+       git rebase HEAD^ &&
+       test_cmp_graph HEAD^.. <<-\EOF
+       *   Merge the topic branch '\''onebranch'\''
+       |\
+       | * D
+       | * G
+       |/
+       o H
+       EOF
+'
+
+test_expect_success '--no-rebase-merges overrides rebase.rebaseMerges=no-rebase-cousins' '
+       test_config rebase.rebaseMerges no-rebase-cousins &&
+       git checkout -b override-config-no-rebase-cousins E &&
+       git rebase --no-rebase-merges C &&
+       test_cmp_graph C.. <<-\EOF
+       * B
+       * D
+       o C
+       EOF
+'
+
+test_expect_success '--rebase-merges overrides rebase.rebaseMerges=rebase-cousins' '
+       test_config rebase.rebaseMerges rebase-cousins &&
+       git checkout -b override-config-rebase-cousins E &&
+       before="$(git rev-parse --verify HEAD)" &&
+       test_tick &&
+       git rebase --rebase-merges C &&
+       test_cmp_rev HEAD $before
+'
+
 test_expect_success 'refs/rewritten/* is worktree-local' '
        git worktree add wt &&
        cat >wt/script-from-scratch <<-\EOF &&
@@ -534,4 +592,23 @@ test_expect_success '--rebase-merges with message matched with onto label' '
        EOF
 '
 
+test_expect_success 'progress shows the correct total' '
+       git checkout -b progress H &&
+       git rebase --rebase-merges --force-rebase --verbose A 2> err &&
+       # Expecting "Rebasing (N/14)" here, no bogus total number
+       grep "^Rebasing.*/14.$" err >progress &&
+       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 2f3e3e2416921c28b27b75dc9f76c20b40401d4d..e2ef6193233dd0b7a2341c391695aabd73d03200 100755 (executable)
@@ -1,14 +1,6 @@
 #!/bin/sh
 
-test_description='test cherry-pick and revert with renames
-
-  --
-   + rename2: renames oops to opos
-  +  rename1: renames oops to spoo
-  +  added:   adds extra line to oops
-  ++ initial: has lines in oops
-
-'
+test_description='miscellaneous basic tests for cherry-pick and revert'
 
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -63,6 +55,14 @@ test_expect_success 'revert --nonsense' '
        test_i18ngrep "[Uu]sage:" msg
 '
 
+# the following two test cherry-pick and revert with renames
+#
+# --
+#  + rename2: renames oops to opos
+# +  rename1: renames oops to spoo
+# +  added:   adds extra line to oops
+# ++ initial: has lines in oops
+
 test_expect_success 'cherry-pick after renaming branch' '
 
        git checkout rename2 &&
index 51afbd7b24a10c247520ba2f9be702da57f83afd..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'
 
@@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' '
 
 test_expect_success '.gitignore is honored' '
        git add . &&
-       ! (git ls-files | grep "\\.ig")
+       git ls-files >files &&
+       sed -n "/\\.ig/p" <files >actual &&
+       test_must_be_empty actual
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
        test_must_fail git add a.?? &&
-       ! (git ls-files | grep "\\.ig")
+       git ls-files >files &&
+       sed -n "/\\.ig/p" <files >actual &&
+       test_must_be_empty actual
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
        test_must_fail git add d.?? &&
-       ! (git ls-files | grep "\\.ig")
+       git ls-files >files &&
+       sed -n "/\\.ig/p" <files >actual &&
+       test_must_be_empty actual
 '
 
 test_expect_success 'error out when attempting to add ignored ones but add others' '
        touch a.if &&
        test_must_fail git add a.?? &&
-       ! (git ls-files | grep "\\.ig") &&
-       (git ls-files | grep a.if)
+       git ls-files >files &&
+       sed -n "/\\.ig/p" <files >actual &&
+       test_must_be_empty actual &&
+       grep a.if files
 '
 
 test_expect_success 'add ignored ones with -f' '
@@ -276,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 3a99837d9b15f78f2f8e034d4fdea9a0b88441ed..34aabb7f5f6a543b31f89650f63b8783e9071271 100755 (executable)
@@ -7,12 +7,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if test_have_prereq !PERL
-then
-       skip_all='skipping add -i (scripted) tests, perl not available'
-       test_done
-fi
-
 diff_cmp () {
        for x
        do
@@ -311,9 +305,11 @@ test_expect_success FILEMODE 'stage mode and hunk' '
        echo content >>file &&
        chmod +x file &&
        printf "y\\ny\\n" | git add -p &&
-       git diff --cached file | grep "new mode" &&
-       git diff --cached file | grep "+content" &&
-       test -z "$(git diff file)"
+       git diff --cached file >out &&
+       grep "new mode" out &&
+       grep "+content" out &&
+       git diff file >out &&
+       test_must_be_empty out
 '
 
 # end of tests disabled when filemode is not usable
@@ -738,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 &&
 
@@ -1075,4 +1109,25 @@ test_expect_success 'show help from add--helper' '
        test_cmp expect actual
 '
 
+test_expect_success 'reset -p with unmerged files' '
+       test_when_finished "git checkout --force main" &&
+       test_commit one conflict &&
+       git checkout -B side HEAD^ &&
+       test_commit two conflict &&
+       test_must_fail git merge one &&
+
+       # this is a noop with only an unmerged entry
+       git reset -p &&
+
+       # add files that sort before and after unmerged entry
+       echo a >a &&
+       echo z >z &&
+       git add a z &&
+
+       # confirm that we can reset those files
+       printf "%s\n" y y | git reset -p &&
+       git diff-index --cached --diff-filter=u HEAD >staged &&
+       test_must_be_empty staged
+'
+
 test_done
index 376cc8f4ab8429b0488ad23b0f9731c9af237124..0b3dfeaea20048426be4d032dd6dc7e66359dc67 100755 (executable)
@@ -1211,19 +1211,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 dfcf3a0aaae3e2a72f6f41023b01c639a99c2f44..5de1d190759f958f8c3c0319f7b4cca34f39d83c 100755 (executable)
@@ -616,4 +616,46 @@ test_expect_success 'diff -I<regex>: detect malformed regex' '
        test_i18ngrep "invalid regex given to -I: " error
 '
 
+# check_prefix <patch> <src> <dst>
+# check only lines with paths to avoid dependency on exact oid/contents
+check_prefix () {
+       grep -E '^(diff|---|\+\+\+) ' "$1" >actual.paths &&
+       cat >expect <<-EOF &&
+       diff --git $2 $3
+       --- $2
+       +++ $3
+       EOF
+       test_cmp expect actual.paths
+}
+
+test_expect_success 'diff-files does not respect diff.noprefix' '
+       git -c diff.noprefix diff-files -p >actual &&
+       check_prefix actual a/file0 b/file0
+'
+
+test_expect_success 'diff-files respects --no-prefix' '
+       git diff-files -p --no-prefix >actual &&
+       check_prefix actual file0 file0
+'
+
+test_expect_success 'diff respects diff.noprefix' '
+       git -c diff.noprefix diff >actual &&
+       check_prefix actual file0 file0
+'
+
+test_expect_success 'diff --default-prefix overrides diff.noprefix' '
+       git -c diff.noprefix diff --default-prefix >actual &&
+       check_prefix actual a/file0 b/file0
+'
+
+test_expect_success 'diff respects diff.mnemonicprefix' '
+       git -c diff.mnemonicprefix diff >actual &&
+       check_prefix actual i/file0 w/file0
+'
+
+test_expect_success 'diff --default-prefix overrides diff.mnemonicprefix' '
+       git -c diff.mnemonicprefix diff --default-prefix >actual &&
+       check_prefix actual a/file0 b/file0
+'
+
 test_done
index f3313b8c58feabb3cd2e52fb1147bd68c6f43862..3cf2b7a7fb70ec272d9f12294a26e2a1685c5999 100755 (executable)
@@ -59,6 +59,10 @@ test_expect_success setup '
        test_tick &&
        git commit -m "patchid 3" &&
 
+       git checkout -b empty main &&
+       test_tick &&
+       git commit --allow-empty -m "empty commit" &&
+
        git checkout main
 '
 
@@ -128,6 +132,12 @@ test_expect_success 'replay did not screw up the log message' '
        grep "^Side .* with .* backslash-n" actual
 '
 
+test_expect_success 'format-patch empty commit' '
+       git format-patch --stdout main..empty >empty &&
+       grep "^From " empty >from &&
+       test_line_count = 1 from
+'
+
 test_expect_success 'extra headers' '
        git config format.headers "To: R E Cipient <rcipient@example.com>
 " &&
@@ -445,13 +455,13 @@ test_expect_success 'no threading' '
 
 cat >expect.thread <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 ---
-Message-Id: <1>
+Message-ID: <1>
 In-Reply-To: <0>
 References: <0>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <0>
 References: <0>
 EOF
@@ -460,17 +470,22 @@ test_expect_success 'thread' '
        check_threading expect.thread --thread main
 '
 
+test_expect_success '--thread overrides format.thread=deep' '
+       test_config format.thread deep &&
+       check_threading expect.thread --thread main
+'
+
 cat >expect.in-reply-to <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 In-Reply-To: <1>
 References: <1>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <1>
 References: <1>
 ---
-Message-Id: <3>
+Message-ID: <3>
 In-Reply-To: <1>
 References: <1>
 EOF
@@ -482,17 +497,17 @@ test_expect_success 'thread in-reply-to' '
 
 cat >expect.cover-letter <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 ---
-Message-Id: <1>
+Message-ID: <1>
 In-Reply-To: <0>
 References: <0>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <0>
 References: <0>
 ---
-Message-Id: <3>
+Message-ID: <3>
 In-Reply-To: <0>
 References: <0>
 EOF
@@ -503,21 +518,21 @@ test_expect_success 'thread cover-letter' '
 
 cat >expect.cl-irt <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 In-Reply-To: <1>
 References: <1>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <0>
 References: <1>
        <0>
 ---
-Message-Id: <3>
+Message-ID: <3>
 In-Reply-To: <0>
 References: <1>
        <0>
 ---
-Message-Id: <4>
+Message-ID: <4>
 In-Reply-To: <0>
 References: <1>
        <0>
@@ -535,13 +550,13 @@ test_expect_success 'thread explicit shallow' '
 
 cat >expect.deep <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 ---
-Message-Id: <1>
+Message-ID: <1>
 In-Reply-To: <0>
 References: <0>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <1>
 References: <0>
        <1>
@@ -553,16 +568,16 @@ test_expect_success 'thread deep' '
 
 cat >expect.deep-irt <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 In-Reply-To: <1>
 References: <1>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <0>
 References: <1>
        <0>
 ---
-Message-Id: <3>
+Message-ID: <3>
 In-Reply-To: <2>
 References: <1>
        <0>
@@ -576,18 +591,18 @@ test_expect_success 'thread deep in-reply-to' '
 
 cat >expect.deep-cl <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 ---
-Message-Id: <1>
+Message-ID: <1>
 In-Reply-To: <0>
 References: <0>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <1>
 References: <0>
        <1>
 ---
-Message-Id: <3>
+Message-ID: <3>
 In-Reply-To: <2>
 References: <0>
        <1>
@@ -600,22 +615,22 @@ test_expect_success 'thread deep cover-letter' '
 
 cat >expect.deep-cl-irt <<EOF
 ---
-Message-Id: <0>
+Message-ID: <0>
 In-Reply-To: <1>
 References: <1>
 ---
-Message-Id: <2>
+Message-ID: <2>
 In-Reply-To: <0>
 References: <1>
        <0>
 ---
-Message-Id: <3>
+Message-ID: <3>
 In-Reply-To: <2>
 References: <1>
        <0>
        <2>
 ---
-Message-Id: <4>
+Message-ID: <4>
 In-Reply-To: <3>
 References: <1>
        <0>
@@ -2386,4 +2401,20 @@ test_expect_success 'interdiff: solo-patch' '
        test_cmp expect actual
 '
 
+test_expect_success 'format-patch does not respect diff.noprefix' '
+       git -c diff.noprefix format-patch -1 --stdout >actual &&
+       grep "^--- a/blorp" actual
+'
+
+test_expect_success 'format-patch respects format.noprefix' '
+       git -c format.noprefix format-patch -1 --stdout >actual &&
+       grep "^--- blorp" actual
+'
+
+test_expect_success 'format-patch --default-prefix overrides format.noprefix' '
+       git -c format.noprefix \
+               format-patch -1 --default-prefix --stdout >actual &&
+       grep "^--- a/blorp" actual
+'
+
 test_done
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 42a2b9a13b7a5bd6cf28cfbe9bbfb9a5a3e5f3e6..c8d555771d5072f95185f48898b59a7e88ddcd26 100755 (executable)
@@ -63,6 +63,25 @@ do
                test_i18ngrep ! fatal msg &&
                test_i18ngrep ! error msg
        '
+
+       test_expect_success "builtin $p pattern compiles on bare repo with --attr-source" '
+               test_when_finished "rm -rf bare.git" &&
+               git checkout -B master &&
+               git add . &&
+               echo "*.java diff=notexist" >.gitattributes &&
+               git add .gitattributes &&
+               git commit -am "changing gitattributes" &&
+               git checkout -B branchA &&
+               echo "*.java diff=$p" >.gitattributes &&
+               git add .gitattributes &&
+               git commit -am "changing gitattributes" &&
+               git clone --bare --no-local . bare.git &&
+               git -C bare.git symbolic-ref HEAD refs/heads/master &&
+               test_expect_code 1 git -C bare.git --attr-source=branchA \
+                       diff --exit-code HEAD:A.java HEAD:B.java 2>msg &&
+               test_i18ngrep ! fatal msg &&
+               test_i18ngrep ! error msg
+       '
 done
 
 test_expect_success 'last regexp must not be negated' '
index 1c89050a974c7b101056865a4b48e7f18a90d29e..6fed993ea0b34dddae94356354c889ada9f16497 100755 (executable)
@@ -24,7 +24,7 @@ test_expect_success setup '
 test_expect_success 'detect rewrite' '
 
        actual=$(git diff-files -B --summary test) &&
-       verbose expr "$actual" : " rewrite test ([0-9]*%)$"
+       expr "$actual" : " rewrite test ([0-9]*%)$"
 
 '
 
index 15764ee9ac8ab7984e57473a121be595c2e9b0cc..74586f3813c6f44955a5407e0d3382febd9e4e58 100755 (executable)
@@ -69,6 +69,10 @@ test_language_driver () {
                echo "* diff='"$lang"'" >.gitattributes &&
                word_diff --color-words
        '
+       test_expect_success "diff driver '$lang' in Islandic" '
+               LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \
+               word_diff --color-words
+       '
 }
 
 test_expect_success setup '
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 7fec2cb9cd783f5aeff27236c8e54ddb2241e1be..70224c3da1494262eb4b2a46c58e001d74f37a9e 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='diff --dirstat tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # set up two commits where the second commit has these files
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 9aaa068ed9bc9a7853ce8331ec5d66107a50b94b..a90b46b678ca35a6af71769149bcfa7cc2317a39 100755 (executable)
@@ -24,7 +24,7 @@ test_expect_success '-G matches' '
 
 test_expect_success '-S --pickaxe-regex' '
        git diff --name-only -S0 --pickaxe-regex HEAD^ >out &&
-       verbose test 4096-zeroes.txt = "$(cat out)"
+       test 4096-zeroes.txt = "$(cat out)"
 '
 
 test_done
index f60f5cbd65f049e1d3148bae352f3c6032454f2e..7af3a08862dec8a17b113191a3dbea56b0995cd3 100755 (executable)
@@ -151,7 +151,7 @@ test_expect_success 'diff does not fetch anything if inexact rename detection is
 
        # Ensure no fetches.
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD &&
-       ! test_path_exists trace
+       test_path_is_missing trace
 '
 
 test_expect_success 'diff --break-rewrites fetches only if necessary, and batches blobs if it does' '
@@ -171,7 +171,7 @@ test_expect_success 'diff --break-rewrites fetches only if necessary, and batche
 
        # Ensure no fetches.
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD &&
-       ! test_path_exists trace &&
+       test_path_is_missing trace &&
 
        # But with --break-rewrites, ensure that there is exactly 1 negotiation
        # by checking that there is only 1 "done" line sent. ("done" marks the
index e95e6d4e7d6419236c1e8bb9bc519b05ea8efec3..a22a90d552a8ac8beb61d02b6e373a43951be7a1 100755 (executable)
@@ -74,7 +74,7 @@ test_expect_success SYMLINKS 'symlink escape when creating new files' '
        error: affected file ${SQ}renamed-symlink/create-me${SQ} is beyond a symbolic link
        EOF
        test_cmp expected_stderr stderr &&
-       ! test_path_exists .git/create-me
+       test_path_is_missing .git/create-me
 '
 
 test_expect_success SYMLINKS 'symlink escape when modifying file' '
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 78cf1c880e69832ecd796ec11af8eff6ce19bd80..2935fe1b2d63e758e91711a98d90f942a07e032c 100755 (executable)
@@ -103,7 +103,7 @@ test_expect_success setup '
 
        git format-patch --stdout first >patch1 &&
        {
-               echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
+               echo "Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
                echo "X-Fake-Field: Line One" &&
                echo "X-Fake-Field: Line Two" &&
                echo "X-Fake-Field: Line Three" &&
@@ -942,7 +942,7 @@ test_expect_success 'am --message-id really adds the message id' '
        git am --message-id patch1.eml &&
        test_path_is_missing .git/rebase-apply &&
        git cat-file commit HEAD | tail -n1 >actual &&
-       grep Message-Id patch1.eml >expected &&
+       grep Message-ID patch1.eml >expected &&
        test_cmp expected actual
 '
 
@@ -954,7 +954,7 @@ test_expect_success 'am.messageid really adds the message id' '
        git am patch1.eml &&
        test_path_is_missing .git/rebase-apply &&
        git cat-file commit HEAD | tail -n1 >actual &&
-       grep Message-Id patch1.eml >expected &&
+       grep Message-ID patch1.eml >expected &&
        test_cmp expected actual
 '
 
@@ -965,7 +965,7 @@ test_expect_success 'am --message-id -s signs off after the message id' '
        git am -s --message-id patch1.eml &&
        test_path_is_missing .git/rebase-apply &&
        git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
-       grep Message-Id patch1.eml >expected &&
+       grep Message-ID patch1.eml >expected &&
        test_cmp expected actual
 '
 
index 2ce2b41174d501f998b9e9edb4faa8ba969629f6..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 &&
@@ -835,6 +850,21 @@ test_expect_success 'log.decorate configuration' '
 
 '
 
+test_expect_success 'parse log.excludeDecoration with no value' '
+       cp .git/config .git/config.orig &&
+       test_when_finished mv .git/config.orig .git/config &&
+
+       cat >>.git/config <<-\EOF &&
+       [log]
+               excludeDecoration
+       EOF
+       cat >expect <<-\EOF &&
+       error: missing value for '\''log.excludeDecoration'\''
+       EOF
+       git log --decorate=short 2>actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'decorate-refs with glob' '
        cat >expect.decorate <<-\EOF &&
        Merge-tag-reach
@@ -2328,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..dd9035aa384937bfec5793fe2f591032282837ac 100755 (executable)
@@ -1012,10 +1012,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 e89e1f54b6caed2e97d04aaf4672a0491a398acf..85e90acb0919d6bff674263aff7f2d5140bc0495 100755 (executable)
@@ -8,8 +8,9 @@ TEST_PASSES_SANITIZE_LEAK=true
 test_expect_success 'setup' '
        test_commit foo &&
 
-       git cat-file commit HEAD |
-       sed "/^author /s/>/>-<>/" >broken_email.commit &&
+       git cat-file commit HEAD >ok.commit &&
+       sed "s/>/>-<>/" <ok.commit >broken_email.commit &&
+
        git hash-object --literally -w -t commit broken_email.commit >broken_email.hash &&
        git update-ref refs/heads/broken_email $(cat broken_email.hash)
 '
@@ -43,6 +44,11 @@ test_expect_success 'git log --format with broken author email' '
        test_must_be_empty actual.err
 '
 
+test_expect_success '--until handles broken email' '
+       git rev-list --until=1980-01-01 broken_email >actual &&
+       test_must_be_empty actual
+'
+
 munge_author_date () {
        git cat-file commit "$1" >commit.orig &&
        sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge &&
@@ -86,4 +92,45 @@ test_expect_success 'absurdly far-in-future date' '
        git log -1 --format=%ad $commit
 '
 
+test_expect_success 'create commits with whitespace committer dates' '
+       # It is important that this subject line is numeric, since we want to
+       # be sure we are not confused by skipping whitespace and accidentally
+       # parsing the subject as a timestamp.
+       #
+       # Do not use munge_author_date here. Besides not hitting the committer
+       # line, it leaves the timezone intact, and we want nothing but
+       # whitespace.
+       #
+       # We will make two munged commits here. The first, ws_commit, will
+       # be purely spaces. The second contains a vertical tab, which is
+       # considered a space by strtoumax(), but not by our isspace().
+       test_commit 1234567890 &&
+       git cat-file commit HEAD >commit.orig &&
+       sed "s/>.*/>    /" <commit.orig >commit.munge &&
+       ws_commit=$(git hash-object --literally -w -t commit commit.munge) &&
+       sed "s/>.*/>   $(printf "\013")/" <commit.orig >commit.munge &&
+       vt_commit=$(git hash-object --literally -w -t commit commit.munge)
+'
+
+test_expect_success '--until treats whitespace date as sentinel' '
+       echo $ws_commit >expect &&
+       git rev-list --until=1980-01-01 $ws_commit >actual &&
+       test_cmp expect actual &&
+
+       echo $vt_commit >expect &&
+       git rev-list --until=1980-01-01 $vt_commit >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'pretty-printer handles whitespace date' '
+       # as with the %ad test above, we will show these as the empty string,
+       # not the 1970 epoch date. This is intentional; see 7d9a281941 (t4212:
+       # test bogus timestamps with git-log, 2014-02-24) for more discussion.
+       echo : >expect &&
+       git log -1 --format="%at:%ct" $ws_commit >actual &&
+       test_cmp expect actual &&
+       git log -1 --format="%at:%ct" $vt_commit >actual &&
+       test_cmp expect actual
+'
+
 test_done
index c62819f3d25afc78aaed385d9bd79afe30060692..1ae528ba78fb130d6a73b314502697c1b1dc81c0 100644 (file)
@@ -2,7 +2,7 @@ From: A U Thor <mail@example.com>
 To: list@example.org
 Subject: [PATCH v2] sample
 Date: Mon,  3 Aug 2020 22:40:55 +0700
-Message-Id: <msg-id@example.com>
+Message-ID: <msg-id@example.com>
 Content-Type: text/plain; charset="utf-8"
 Content-Transfer-Encoding: base64
 
index c52c8a21fae6d0593cc120485e8d6eaa8a95ccbc..57c4f26e4613a97644ad5822b1f6a0c4572a33a4 100755 (executable)
@@ -334,4 +334,22 @@ test_expect_success 'turn tree to file' '
        test_cmp expect actual
 '
 
+test_expect_success 'merge-tree respects core.useReplaceRefs=false' '
+       test_commit merge-to &&
+       test_commit valid base &&
+       git reset --hard HEAD^ &&
+       test_commit malicious base &&
+
+       test_when_finished "git replace -d $(git rev-parse valid^0)" &&
+       git replace valid^0 malicious^0 &&
+
+       tree=$(git -c core.useReplaceRefs=true merge-tree --write-tree merge-to valid) &&
+       merged=$(git cat-file -p $tree:base) &&
+       test malicious = $merged &&
+
+       tree=$(git -c core.useReplaceRefs=false merge-tree --write-tree merge-to valid) &&
+       merged=$(git cat-file -p $tree:base) &&
+       test valid = $merged
+'
+
 test_done
index 918a2fc7c69432c26e3135460d62f9b27f0e3dbd..4b4c3315d885f02fdcf2be65885ea9107f65b86d 100755 (executable)
@@ -185,6 +185,7 @@ test_expect_success 'git archive' '
 '
 
 check_tar b
+check_mtime b a/a 1117231200
 
 test_expect_success 'git archive --mtime' '
        git archive --mtime=2002-02-02T02:02:02-0200 HEAD >with_mtime.tar
@@ -257,14 +258,6 @@ test_expect_success 'git archive --remote with configured remote' '
        test_cmp_bin b.tar b5-nick.tar
 '
 
-test_expect_success 'validate file modification time' '
-       mkdir extract &&
-       "$TAR" xf b.tar -C extract a/a &&
-       test-tool chmtime --get extract/a/a >b.mtime &&
-       echo "1117231200" >expected.mtime &&
-       test_cmp expected.mtime b.mtime
-'
-
 test_expect_success 'git get-tar-commit-id' '
        git get-tar-commit-id <b.tar >actual &&
        git rev-parse HEAD >expect &&
@@ -433,6 +426,19 @@ test_expect_success 'catch non-matching pathspec' '
        test_must_fail git archive -v HEAD -- "*.abc" >/dev/null
 '
 
+test_expect_success 'reject paths outside the current directory' '
+       test_must_fail git -C a/bin archive HEAD .. >/dev/null 2>err &&
+       grep "outside the current directory" err
+'
+
+test_expect_success 'allow pathspecs that resolve to the current directory' '
+       git -C a/bin archive -v HEAD ../bin >/dev/null 2>actual &&
+       cat >expect <<-\EOF &&
+       sh
+       EOF
+       test_cmp expect actual
+'
+
 # Pull the size and date of each entry in a tarfile using the system tar.
 #
 # We'll pull out only the year from the date; that avoids any question of
index 04d300eeda760033c0e72beb2aee1235c664c457..0ff47a239db905eb5c3e65de53994b0ac81cbd86 100755 (executable)
@@ -33,6 +33,13 @@ test_expect_success 'setup' '
        echo ignored-by-tree.d export-ignore >>.gitattributes &&
        git add ignored-by-tree ignored-by-tree.d .gitattributes &&
 
+       mkdir subdir &&
+       >subdir/included &&
+       >subdir/ignored-by-subtree &&
+       >subdir/ignored-by-tree &&
+       echo ignored-by-subtree export-ignore >subdir/.gitattributes &&
+       git add subdir &&
+
        echo ignored by worktree >ignored-by-worktree &&
        echo ignored-by-worktree export-ignore >.gitattributes &&
        git add ignored-by-worktree &&
@@ -93,6 +100,15 @@ test_expect_exists  archive-pathspec-wildcard/ignored-by-worktree
 test_expect_missing    archive-pathspec-wildcard/excluded-by-pathspec.d
 test_expect_missing    archive-pathspec-wildcard/excluded-by-pathspec.d/file
 
+test_expect_success 'git -C subdir archive' '
+       git -C subdir archive HEAD >archive-subdir.tar &&
+       extract_tar_to_dir archive-subdir
+'
+
+test_expect_exists     archive-subdir/included
+test_expect_missing    archive-subdir/ignored-by-subtree
+test_expect_missing    archive-subdir/ignored-by-tree
+
 test_expect_success 'git archive with worktree attributes' '
        git archive --worktree-attributes HEAD >worktree.tar &&
        (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar
index e2546ec7332b6b0483f4951906a40436da6383e0..1089382425e481e343064d401bb635407c79e5b4 100644 (file)
@@ -3,7 +3,7 @@ message:
 
 From: Nit Picker <nit.picker@example.net>
 Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
 
 Hopefully this would fix the problem stated there.
 
index 1ac68101b135f4aaf6dacd4bcc0b7586a29d6584..3402b534a6a060c87af0dd5cb6cdc12a4f703835 100644 (file)
@@ -3,7 +3,7 @@ message:
 
 From: Nit Picker <nit.picker@example.net>
 Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
 
 Hopefully this would fix the problem stated there.
 
index 376e26e9aeba074a7f9a240449af1874726e7f44..44482958ce711988d9d72a183c8f11133a896881 100644 (file)
@@ -5,4 +5,4 @@ docutils заменён на python-docutils
 python-docutils. В то время как сам rest2web не нужен.
 
 Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru>
-Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
+Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
index 909021bb7a8de1bf5ce619517b1facc715dfdc4d..a529d4de08863ef78bc32a15d5c90d761e1e5b28 100644 (file)
@@ -3,7 +3,7 @@ From: A U Thor <mail@example.com>
 To: list@example.org
 Subject: [PATCH v2] sample
 Date: Mon,  3 Aug 2020 22:40:55 +0700
-Message-Id: <msg-id@example.com>
+Message-ID: <msg-id@example.com>
 Content-Type: text/plain; charset="utf-8"
 Content-Transfer-Encoding: base64
 
@@ -27,7 +27,7 @@ From: A U Thor <mail@example.com>
 To: list@example.org
 Subject: [PATCH v2] sample
 Date: Mon,  3 Aug 2020 22:40:55 +0700
-Message-Id: <msg-id2@example.com>
+Message-ID: <msg-id2@example.com>
 Content-Type: text/plain; charset="utf-8"
 Content-Transfer-Encoding: base64
 
index 6d4d0e44742ed3a162b1f9c813b0ad41b6f7dc7a..4a54ee517198cf218d330bdc4cd93cd279abcf0e 100644 (file)
@@ -35,7 +35,7 @@ message:
 
 From: Nit Picker <nit.picker@example.net>
 Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
 
 Hopefully this would fix the problem stated there.
 
@@ -78,7 +78,7 @@ message:
 
 From: Nit Picker <nit.picker@example.net>
 Subject: foo is too old
-Message-Id: <nitpicker.12121212@example.net>
+Message-ID: <nitpicker.12121212@example.net>
 
 Hopefully this would fix the problem stated there.
 
@@ -508,7 +508,7 @@ From bda@mnsspb.ru Wed Nov 12 17:54:41 2008
 From: Dmitriy Blinov <bda@mnsspb.ru>
 To: navy-patches@dinar.mns.mnsspb.ru
 Date: Wed, 12 Nov 2008 17:54:41 +0300
-Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
+Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
 X-Mailer: git-send-email 1.5.6.5
 MIME-Version: 1.0
 Content-Type: text/plain;
index f8a0f309e2dec0f2ab864851730446bdc7102818..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' '
 
@@ -589,141 +589,6 @@ test_expect_success 'prefetch objects' '
        test_line_count = 1 donelines
 '
 
-test_expect_success 'setup for --stdin-packs tests' '
-       git init stdin-packs &&
-       (
-               cd stdin-packs &&
-
-               test_commit A &&
-               test_commit B &&
-               test_commit C &&
-
-               for id in A B C
-               do
-                       git pack-objects .git/objects/pack/pack-$id \
-                               --incremental --revs <<-EOF || exit 1
-                       refs/tags/$id
-                       EOF
-               done &&
-
-               ls -la .git/objects/pack
-       )
-'
-
-test_expect_success '--stdin-packs with excluded packs' '
-       (
-               cd stdin-packs &&
-
-               PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
-               PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
-               PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
-
-               git pack-objects test --stdin-packs <<-EOF &&
-               $PACK_A
-               ^$PACK_B
-               $PACK_C
-               EOF
-
-               (
-                       git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
-                       git show-index <$(ls .git/objects/pack/pack-C-*.idx)
-               ) >expect.raw &&
-               git show-index <$(ls test-*.idx) >actual.raw &&
-
-               cut -d" " -f2 <expect.raw | sort >expect &&
-               cut -d" " -f2 <actual.raw | sort >actual &&
-               test_cmp expect actual
-       )
-'
-
-test_expect_success '--stdin-packs is incompatible with --filter' '
-       (
-               cd stdin-packs &&
-               test_must_fail git pack-objects --stdin-packs --stdout \
-                       --filter=blob:none </dev/null 2>err &&
-               test_i18ngrep "cannot use --filter with --stdin-packs" err
-       )
-'
-
-test_expect_success '--stdin-packs is incompatible with --revs' '
-       (
-               cd stdin-packs &&
-               test_must_fail git pack-objects --stdin-packs --revs out \
-                       </dev/null 2>err &&
-               test_i18ngrep "cannot use internal rev list with --stdin-packs" err
-       )
-'
-
-test_expect_success '--stdin-packs with loose objects' '
-       (
-               cd stdin-packs &&
-
-               PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
-               PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
-               PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
-
-               test_commit D && # loose
-
-               git pack-objects test2 --stdin-packs --unpacked <<-EOF &&
-               $PACK_A
-               ^$PACK_B
-               $PACK_C
-               EOF
-
-               (
-                       git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
-                       git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
-                       git rev-list --objects --no-object-names \
-                               refs/tags/C..refs/tags/D
-
-               ) >expect.raw &&
-               ls -la . &&
-               git show-index <$(ls test2-*.idx) >actual.raw &&
-
-               cut -d" " -f2 <expect.raw | sort >expect &&
-               cut -d" " -f2 <actual.raw | sort >actual &&
-               test_cmp expect actual
-       )
-'
-
-test_expect_success '--stdin-packs with broken links' '
-       (
-               cd stdin-packs &&
-
-               # make an unreachable object with a bogus parent
-               git cat-file -p HEAD >commit &&
-               sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit |
-               git hash-object -w -t commit --stdin >in &&
-
-               git pack-objects .git/objects/pack/pack-D <in &&
-
-               PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
-               PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
-               PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
-               PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" &&
-
-               git pack-objects test3 --stdin-packs --unpacked <<-EOF &&
-               $PACK_A
-               ^$PACK_B
-               $PACK_C
-               $PACK_D
-               EOF
-
-               (
-                       git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
-                       git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
-                       git show-index <$(ls .git/objects/pack/pack-D-*.idx) &&
-                       git rev-list --objects --no-object-names \
-                               refs/tags/C..refs/tags/D
-               ) >expect.raw &&
-               git show-index <$(ls test3-*.idx) >actual.raw &&
-
-               cut -d" " -f2 <expect.raw | sort >expect &&
-               cut -d" " -f2 <actual.raw | sort >actual &&
-               test_cmp expect actual
-       )
-'
-
 test_expect_success 'negative window clamps to 0' '
        git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr &&
        check_deltas stderr = 0
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 d65a5f94b4b557ef9cce4434594729086cb51fad..b4df545e5ab602a869cfde5d13090e40c6d003a5 100755 (executable)
@@ -16,7 +16,7 @@ add_blob() {
        before=$(git count-objects | sed "s/ .*//") &&
        BLOB=$(echo aleph_0 | git hash-object -w --stdin) &&
        BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
-       verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+       test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
        test_path_is_file $BLOB_FILE &&
        test-tool chmtime =+0 $BLOB_FILE
 }
@@ -51,34 +51,42 @@ test_expect_success 'prune stale packs' '
 test_expect_success 'prune --expire' '
        add_blob &&
        git prune --expire=1.hour.ago &&
-       verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+       test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
        test_path_is_file $BLOB_FILE &&
        test-tool chmtime =-86500 $BLOB_FILE &&
        git prune --expire 1.day &&
-       verbose test $before = $(git count-objects | sed "s/ .*//") &&
+       test $before = $(git count-objects | sed "s/ .*//") &&
        test_path_is_missing $BLOB_FILE
 '
 
 test_expect_success 'gc: implicit prune --expire' '
        add_blob &&
        test-tool chmtime =-$((2*$week-30)) $BLOB_FILE &&
-       git gc &&
-       verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+       git gc --no-cruft &&
+       test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
        test_path_is_file $BLOB_FILE &&
        test-tool chmtime =-$((2*$week+1)) $BLOB_FILE &&
-       git gc &&
-       verbose test $before = $(git count-objects | sed "s/ .*//") &&
+       git gc --no-cruft &&
+       test $before = $(git count-objects | sed "s/ .*//") &&
        test_path_is_missing $BLOB_FILE
 '
 
 test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '
-       git config gc.pruneExpire invalid &&
-       test_must_fail git gc
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       >repo/.git/config &&
+       git -C repo config gc.pruneExpire invalid &&
+       cat >expect <<-\EOF &&
+       error: Invalid gc.pruneexpire: '\''invalid'\''
+       fatal: bad config variable '\''gc.pruneexpire'\'' in file '\''.git/config'\'' at line 2
+       EOF
+       test_must_fail git -C repo gc 2>actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'gc: start with ok gc.pruneExpire' '
        git config gc.pruneExpire 2.days.ago &&
-       git gc
+       git gc --no-cruft
 '
 
 test_expect_success 'prune: prune nonsense parameters' '
@@ -129,44 +137,44 @@ test_expect_success 'gc --no-prune' '
        add_blob &&
        test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
        git config gc.pruneExpire 2.days.ago &&
-       git gc --no-prune &&
-       verbose test 1 = $(git count-objects | sed "s/ .*//") &&
+       git gc --no-prune --no-cruft &&
+       test 1 = $(git count-objects | sed "s/ .*//") &&
        test_path_is_file $BLOB_FILE
 '
 
 test_expect_success 'gc respects gc.pruneExpire' '
        git config gc.pruneExpire 5002.days.ago &&
-       git gc &&
+       git gc --no-cruft &&
        test_path_is_file $BLOB_FILE &&
        git config gc.pruneExpire 5000.days.ago &&
-       git gc &&
+       git gc --no-cruft &&
        test_path_is_missing $BLOB_FILE
 '
 
 test_expect_success 'gc --prune=<date>' '
        add_blob &&
        test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
-       git gc --prune=5002.days.ago &&
+       git gc --prune=5002.days.ago --no-cruft &&
        test_path_is_file $BLOB_FILE &&
-       git gc --prune=5000.days.ago &&
+       git gc --prune=5000.days.ago --no-cruft &&
        test_path_is_missing $BLOB_FILE
 '
 
 test_expect_success 'gc --prune=never' '
        add_blob &&
-       git gc --prune=never &&
+       git gc --prune=never --no-cruft &&
        test_path_is_file $BLOB_FILE &&
-       git gc --prune=now &&
+       git gc --prune=now --no-cruft &&
        test_path_is_missing $BLOB_FILE
 '
 
 test_expect_success 'gc respects gc.pruneExpire=never' '
        git config gc.pruneExpire never &&
        add_blob &&
-       git gc &&
+       git gc --no-cruft &&
        test_path_is_file $BLOB_FILE &&
        git config gc.pruneExpire now &&
-       git gc &&
+       git gc --no-cruft &&
        test_path_is_missing $BLOB_FILE
 '
 
@@ -184,10 +192,10 @@ test_expect_success 'gc: prune old objects after local clone' '
        git clone --no-hardlinks . aclone &&
        (
                cd aclone &&
-               verbose test 1 = $(git count-objects | sed "s/ .*//") &&
+               test 1 = $(git count-objects | sed "s/ .*//") &&
                test_path_is_file $BLOB_FILE &&
-               git gc --prune &&
-               verbose test 0 = $(git count-objects | sed "s/ .*//") &&
+               git gc --prune --no-cruft &&
+               test 0 = $(git count-objects | sed "s/ .*//") &&
                test_path_is_missing $BLOB_FILE
        )
 '
@@ -229,7 +237,7 @@ test_expect_success 'clean pack garbage with gc' '
        >.git/objects/pack/fake2.keep &&
        >.git/objects/pack/fake2.idx &&
        >.git/objects/pack/fake3.keep &&
-       git gc &&
+       git gc --no-cruft &&
        git count-objects -v 2>stderr &&
        grep "^warning:" stderr | sort >actual &&
        cat >expected <<\EOF &&
@@ -342,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 7d8dee41b0ded364d9b364ab46296c20b2c8eee1..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/|')"
 }
@@ -404,6 +408,26 @@ test_bitmap_cases () {
                )
        '
 
+       test_expect_success 'pack.preferBitmapTips' '
+               git init repo &&
+               test_when_finished "rm -rf repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+                       test_commit_bulk --message="%s" 103 &&
+
+                       cat >>.git/config <<-\EOF &&
+                       [pack]
+                               preferBitmapTips
+                       EOF
+                       cat >expect <<-\EOF &&
+                       error: missing value for '\''pack.preferbitmaptips'\''
+                       EOF
+                       git repack -adb 2>actual &&
+                       test_cmp expect actual
+               )
+       '
+
        test_expect_success 'complains about multiple pack bitmaps' '
                rm -fr repo &&
                git init repo &&
@@ -437,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 &&
@@ -448,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 049c5fc8ead328860ef7ed38dea410f4524107c9..ba65f17dd9cc863a9a92ae90393af3ffdd2309de 100755 (executable)
@@ -24,12 +24,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 +35,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 +64,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 +178,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 +188,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 +211,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 +328,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 +352,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 +394,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 +422,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 +450,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 +496,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"
 '
 
@@ -628,11 +597,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" \
-               "non-zero generation number"
-'
-
 test_expect_success 'detect incorrect commit date' '
        corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATE "\01" \
                "commit date"
@@ -654,34 +618,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 +763,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
index 499d5d4c78590ae16879d8dbd386259d847efb76..1bcc02004d7d1acbce8306bdeb5439f4da689ccb 100755 (executable)
@@ -183,6 +183,18 @@ test_expect_success 'write midx with --stdin-packs' '
 
 compare_results_with_midx "mixed mode (one pack + extra)"
 
+test_expect_success 'write with no objects and preferred pack' '
+       test_when_finished "rm -rf empty" &&
+       git init empty &&
+       test_must_fail git -C empty multi-pack-index write \
+               --stdin-packs --preferred-pack=does-not-exist </dev/null 2>err &&
+       cat >expect <<-EOF &&
+       warning: unknown preferred pack: ${SQ}does-not-exist${SQ}
+       error: no pack files to index.
+       EOF
+       test_cmp expect err
+'
+
 test_expect_success 'write progress off for redirected stderr' '
        git multi-pack-index --object-dir=$objdir write 2>err &&
        test_line_count = 0 err
@@ -473,6 +485,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" &&
index 669ddc645faccfc402b04044ed75676592e64356..36c4141e67b8f0f5aaf87443ab0c00f2bbd67836 100755 (executable)
@@ -351,7 +351,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 d042d26f2b393d52049ba3c9972e2516b03ed239..431a603ca0e61d7085f28333c6a28c120ea45828 100755 (executable)
@@ -1,17 +1,20 @@
 #!/bin/sh
 
 test_description='on-disk reverse index'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # The below tests want control over the 'pack.writeReverseIndex' setting
 # themselves to assert various combinations of it with other options.
-sane_unset GIT_TEST_WRITE_REV_INDEX
+sane_unset GIT_TEST_NO_WRITE_REV_INDEX
 
 packdir=.git/objects/pack
 
 test_expect_success 'setup' '
        test_commit base &&
 
+       test_config pack.writeReverseIndex false &&
        pack=$(git pack-objects --all $packdir/pack) &&
        rev=$packdir/pack-$pack.rev &&
 
@@ -94,6 +97,17 @@ test_expect_success 'reverse index is not generated when available on disk' '
                --batch-check="%(objectsize:disk)" <tip
 '
 
+test_expect_success 'reverse index is ignored when pack.readReverseIndex is false' '
+       test_index_pack true &&
+       test_path_is_file $rev &&
+
+       test_config pack.readReverseIndex false &&
+
+       git rev-parse HEAD >tip &&
+       GIT_TEST_REV_INDEX_DIE_ON_DISK=1 git cat-file \
+               --batch-check="%(objectsize:disk)" <tip
+'
+
 test_expect_success 'revindex in-memory vs on-disk' '
        git init repo &&
        test_when_finished "rm -fr repo" &&
@@ -117,4 +131,78 @@ test_expect_success 'revindex in-memory vs on-disk' '
                test_cmp on-disk in-core
        )
 '
+
+test_expect_success 'fsck succeeds on good rev-index' '
+       test_when_finished rm -fr repo &&
+       git init repo &&
+       (
+               cd repo &&
+
+               test_commit commit &&
+               git -c pack.writeReverseIndex=true repack -ad &&
+               git fsck 2>err &&
+               test_must_be_empty err
+       )
+'
+
+test_expect_success 'set up rev-index corruption tests' '
+       git init corrupt &&
+       (
+               cd corrupt &&
+
+               test_commit commit &&
+               git -c pack.writeReverseIndex=true repack -ad &&
+
+               revfile=$(ls .git/objects/pack/pack-*.rev) &&
+               chmod a+w $revfile &&
+               cp $revfile $revfile.bak
+       )
+'
+
+corrupt_rev_and_verify () {
+       (
+               pos="$1" &&
+               value="$2" &&
+               error="$3" &&
+
+               cd corrupt &&
+               revfile=$(ls .git/objects/pack/pack-*.rev) &&
+
+               # Reset to original rev-file.
+               cp $revfile.bak $revfile &&
+
+               printf "$value" | dd of=$revfile bs=1 seek="$pos" conv=notrunc &&
+               test_must_fail git fsck 2>err &&
+               grep "$error" err
+       )
+}
+
+test_expect_success 'fsck catches invalid checksum' '
+       revfile=$(ls corrupt/.git/objects/pack/pack-*.rev) &&
+       orig_size=$(wc -c <$revfile) &&
+       hashpos=$((orig_size - 10)) &&
+       corrupt_rev_and_verify $hashpos bogus \
+               "invalid checksum"
+'
+
+test_expect_success 'fsck catches invalid row position' '
+       corrupt_rev_and_verify 14 "\07" \
+               "invalid rev-index position"
+'
+
+test_expect_success 'fsck catches invalid header: magic number' '
+       corrupt_rev_and_verify 1 "\07" \
+               "reverse-index file .* has unknown signature"
+'
+
+test_expect_success 'fsck catches invalid header: version' '
+       corrupt_rev_and_verify 7 "\02" \
+               "reverse-index file .* has unsupported version"
+'
+
+test_expect_success 'fsck catches invalid header: hash function' '
+       corrupt_rev_and_verify 11 "\03" \
+               "reverse-index file .* has unsupported hash id"
+'
+
 test_done
index 0882cbb6e4a4e4803fd1874699e03a2c0940fb13..70d1b58709a91199bf6d589e141897ca96204547 100755 (executable)
@@ -434,4 +434,83 @@ test_expect_success 'tagged commits are selected for bitmapping' '
        )
 '
 
+corrupt_file () {
+       chmod a+w "$1" &&
+       printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc
+}
+
+test_expect_success 'git fsck correctly identifies good and bad bitmaps' '
+       git init valid &&
+       test_when_finished rm -rf valid &&
+
+       test_commit_bulk 20 &&
+       git repack -adbf &&
+
+       # Move pack-bitmap aside so it is not deleted
+       # in next repack.
+       packbitmap=$(ls .git/objects/pack/pack-*.bitmap) &&
+       mv "$packbitmap" "$packbitmap.bak" &&
+
+       test_commit_bulk 10 &&
+       git repack -b --write-midx &&
+       midxbitmap=$(ls .git/objects/pack/multi-pack-index-*.bitmap) &&
+
+       # Copy MIDX bitmap to backup. Copy pack bitmap from backup.
+       cp "$midxbitmap" "$midxbitmap.bak" &&
+       cp "$packbitmap.bak" "$packbitmap" &&
+
+       # fsck works at first
+       git fsck 2>err &&
+       test_must_be_empty err &&
+
+       corrupt_file "$packbitmap" &&
+       test_must_fail git fsck 2>err &&
+       grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err &&
+
+       cp "$packbitmap.bak" "$packbitmap" &&
+       corrupt_file "$midxbitmap" &&
+       test_must_fail git fsck 2>err &&
+       grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err &&
+
+       corrupt_file "$packbitmap" &&
+       test_must_fail git fsck 2>err &&
+       grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err &&
+       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 093f0c067af6801e3334152fe65b7c4495830d30..e9c521c061c3eae86619f4eb931d40f5e3127d35 100755 (executable)
@@ -37,30 +37,39 @@ 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 &&
+       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_done
index 303f7a5d842d36edb191bb05ec61df9a6af8d7c9..45667d4999a97f7ec3221a89bcba579ef3871b3d 100755 (executable)
@@ -739,4 +739,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
diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh
new file mode 100755 (executable)
index 0000000..acab316
--- /dev/null
@@ -0,0 +1,240 @@
+#!/bin/sh
+
+test_description='pack-objects --stdin'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+packed_objects () {
+       git show-index <"$1" >tmp-object-list &&
+       cut -d' ' -f2 tmp-object-list | sort &&
+       rm tmp-object-list
+ }
+
+test_expect_success 'setup for --stdin-packs tests' '
+       git init stdin-packs &&
+       (
+               cd stdin-packs &&
+
+               test_commit A &&
+               test_commit B &&
+               test_commit C &&
+
+               for id in A B C
+               do
+                       git pack-objects .git/objects/pack/pack-$id \
+                               --incremental --revs <<-EOF || exit 1
+                       refs/tags/$id
+                       EOF
+               done &&
+
+               ls -la .git/objects/pack
+       )
+'
+
+test_expect_success '--stdin-packs with excluded packs' '
+       (
+               cd stdin-packs &&
+
+               PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
+               PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
+               PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
+
+               git pack-objects test --stdin-packs <<-EOF &&
+               $PACK_A
+               ^$PACK_B
+               $PACK_C
+               EOF
+
+               (
+                       git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
+                       git show-index <$(ls .git/objects/pack/pack-C-*.idx)
+               ) >expect.raw &&
+               git show-index <$(ls test-*.idx) >actual.raw &&
+
+               cut -d" " -f2 <expect.raw | sort >expect &&
+               cut -d" " -f2 <actual.raw | sort >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '--stdin-packs is incompatible with --filter' '
+       (
+               cd stdin-packs &&
+               test_must_fail git pack-objects --stdin-packs --stdout \
+                       --filter=blob:none </dev/null 2>err &&
+               test_i18ngrep "cannot use --filter with --stdin-packs" err
+       )
+'
+
+test_expect_success '--stdin-packs is incompatible with --revs' '
+       (
+               cd stdin-packs &&
+               test_must_fail git pack-objects --stdin-packs --revs out \
+                       </dev/null 2>err &&
+               test_i18ngrep "cannot use internal rev list with --stdin-packs" err
+       )
+'
+
+test_expect_success '--stdin-packs with loose objects' '
+       (
+               cd stdin-packs &&
+
+               PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
+               PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
+               PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
+
+               test_commit D && # loose
+
+               git pack-objects test2 --stdin-packs --unpacked <<-EOF &&
+               $PACK_A
+               ^$PACK_B
+               $PACK_C
+               EOF
+
+               (
+                       git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
+                       git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
+                       git rev-list --objects --no-object-names \
+                               refs/tags/C..refs/tags/D
+
+               ) >expect.raw &&
+               ls -la . &&
+               git show-index <$(ls test2-*.idx) >actual.raw &&
+
+               cut -d" " -f2 <expect.raw | sort >expect &&
+               cut -d" " -f2 <actual.raw | sort >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '--stdin-packs with broken links' '
+       (
+               cd stdin-packs &&
+
+               # make an unreachable object with a bogus parent
+               git cat-file -p HEAD >commit &&
+               sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit |
+               git hash-object -w -t commit --stdin >in &&
+
+               git pack-objects .git/objects/pack/pack-D <in &&
+
+               PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" &&
+               PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" &&
+               PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" &&
+               PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" &&
+
+               git pack-objects test3 --stdin-packs --unpacked <<-EOF &&
+               $PACK_A
+               ^$PACK_B
+               $PACK_C
+               $PACK_D
+               EOF
+
+               (
+                       git show-index <$(ls .git/objects/pack/pack-A-*.idx) &&
+                       git show-index <$(ls .git/objects/pack/pack-C-*.idx) &&
+                       git show-index <$(ls .git/objects/pack/pack-D-*.idx) &&
+                       git rev-list --objects --no-object-names \
+                               refs/tags/C..refs/tags/D
+               ) >expect.raw &&
+               git show-index <$(ls test3-*.idx) >actual.raw &&
+
+               cut -d" " -f2 <expect.raw | sort >expect &&
+               cut -d" " -f2 <actual.raw | sort >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'pack-objects --stdin with duplicate packfile' '
+       test_when_finished "rm -fr repo" &&
+
+       git init repo &&
+       (
+               cd repo &&
+               test_commit "commit" &&
+               git repack -ad &&
+
+               {
+                       basename .git/objects/pack/pack-*.pack &&
+                       basename .git/objects/pack/pack-*.pack
+               } >packfiles &&
+
+               git pack-objects --stdin-packs generated-pack <packfiles &&
+               packed_objects .git/objects/pack/pack-*.idx >expect &&
+               packed_objects generated-pack-*.idx >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'pack-objects --stdin with same packfile excluded and included' '
+       test_when_finished "rm -fr repo" &&
+
+       git init repo &&
+       (
+               cd repo &&
+               test_commit "commit" &&
+               git repack -ad &&
+
+               {
+                       basename .git/objects/pack/pack-*.pack &&
+                       printf "^%s\n" "$(basename .git/objects/pack/pack-*.pack)"
+               } >packfiles &&
+
+               git pack-objects --stdin-packs generated-pack <packfiles &&
+               packed_objects generated-pack-*.idx >packed-objects &&
+               test_must_be_empty packed-objects
+       )
+'
+
+test_expect_success 'pack-objects --stdin with packfiles from alternate object database' '
+       test_when_finished "rm -fr shared member" &&
+
+       # Set up a shared repository with a single packfile.
+       git init shared &&
+       test_commit -C shared "shared-objects" &&
+       git -C shared repack -ad &&
+       basename shared/.git/objects/pack/pack-*.pack >packfile &&
+
+       # Set up a repository that is connected to the shared repository. This
+       # repository has no objects on its own, but we still expect to be able
+       # to pack objects from its alternate.
+       git clone --shared shared member &&
+       git -C member pack-objects --stdin-packs generated-pack <packfile &&
+       test_cmp shared/.git/objects/pack/pack-*.pack member/generated-pack-*.pack
+'
+
+test_expect_success 'pack-objects --stdin with packfiles from main and alternate object database' '
+       test_when_finished "rm -fr shared member" &&
+
+       # Set up a shared repository with a single packfile.
+       git init shared &&
+       test_commit -C shared "shared-commit" &&
+       git -C shared repack -ad &&
+
+       # Set up a repository that is connected to the shared repository. This
+       # repository has a second packfile so that we can verify that it is
+       # possible to write packs that include packfiles from different object
+       # databases.
+       git clone --shared shared member &&
+       test_commit -C member "local-commit" &&
+       git -C member repack -dl &&
+
+       {
+               basename shared/.git/objects/pack/pack-*.pack &&
+               basename member/.git/objects/pack/pack-*.pack
+       } >packfiles &&
+
+       {
+               packed_objects shared/.git/objects/pack/pack-*.idx &&
+               packed_objects member/.git/objects/pack/pack-*.idx
+       } | sort >expected-objects &&
+
+       git -C member pack-objects --stdin-packs generated-pack <packfiles &&
+       packed_objects member/generated-pack-*.idx >actual-objects &&
+       test_cmp expected-objects actual-objects
+'
+
+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 34a1261520c757053bfb64c8aa2104c407514091..19c36b57f4b2d5363599625ea71ee5a9a87509b0 100755 (executable)
@@ -1118,58 +1118,60 @@ test_expect_success 'fetching with auto-gc does not lock up' '
        )
 '
 
-test_expect_success 'fetch aligned output' '
-       git clone . full-output &&
-       test_commit looooooooooooong-tag &&
-       (
-               cd full-output &&
-               git -c fetch.output=full fetch origin >actual 2>&1 &&
-               grep -e "->" actual | cut -c 22- >../actual
-       ) &&
-       cat >expect <<-\EOF &&
-       main                 -> origin/main
-       looooooooooooong-tag -> looooooooooooong-tag
-       EOF
-       test_cmp expect actual
-'
+for section in fetch transfer
+do
+       test_expect_success "$section.hideRefs affects connectivity check" '
+               GIT_TRACE="$PWD"/trace git -c $section.hideRefs=refs -c \
+                       $section.hideRefs="!refs/tags/" fetch &&
+               grep "git rev-list .*--exclude-hidden=fetch" trace
+       '
+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_expect_success 'fetch compact output' '
-       git clone . compact &&
-       test_commit extraaa &&
-       (
-               cd compact &&
-               git -c fetch.output=compact fetch origin >actual 2>&1 &&
-               grep -e "->" actual | cut -c 22- >../actual
-       ) &&
-       cat >expect <<-\EOF &&
-       main       -> origin/*
-       extraaa    -> *
-       EOF
-       test_cmp expect actual
-'
+test_unpack_limit () {
+       store_type=$1
 
-test_expect_success '--no-show-forced-updates' '
-       mkdir forced-updates &&
-       (
-               cd forced-updates &&
-               git init &&
-               test_commit 1 &&
-               test_commit 2
-       ) &&
-       git clone forced-updates forced-update-clone &&
-       git clone forced-updates no-forced-update-clone &&
-       git -C forced-updates reset --hard HEAD~1 &&
-       (
-               cd forced-update-clone &&
-               git fetch --show-forced-updates origin 2>output &&
-               test_i18ngrep "(forced update)" output
-       ) &&
-       (
-               cd no-forced-update-clone &&
-               git fetch --no-show-forced-updates origin 2>output &&
-               test_i18ngrep ! "(forced update)" output
-       )
-'
+       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"
index 20d063fb9ae72c4df77a00dd5d5cb6da65640238..151c76eb09b7831edd803e6cad27dddc4b5489ec 100755 (executable)
@@ -15,6 +15,19 @@ generate_references () {
        done
 }
 
+test_expect_success 'set up fake upload-pack' '
+       # This can be used to simulate an upload-pack that just shows the
+       # contents of the "input" file (prepared with the test-tool pkt-line
+       # helper), and does not do any negotiation (since ls-remote does not
+       # need it).
+       write_script cat-input <<-\EOF
+       # send our initial advertisement/response
+       cat input
+       # soak up the flush packet from the client
+       cat
+       EOF
+'
+
 test_expect_success 'dies when no remote found' '
        test_must_fail git ls-remote
 '
@@ -231,22 +244,25 @@ test_expect_success 'protocol v2 supports hiderefs' '
 
 test_expect_success 'ls-remote --symref' '
        git fetch origin &&
-       echo "ref: refs/heads/main      HEAD" >expect &&
+       echo "ref: refs/heads/main      HEAD" >expect.v2 &&
        generate_references \
                HEAD \
-               refs/heads/main >>expect &&
+               refs/heads/main >>expect.v2 &&
+       echo "ref: refs/remotes/origin/main     refs/remotes/origin/HEAD" >>expect.v2 &&
        oid=$(git rev-parse HEAD) &&
-       echo "$oid      refs/remotes/origin/HEAD" >>expect &&
+       echo "$oid      refs/remotes/origin/HEAD" >>expect.v2 &&
        generate_references \
                refs/remotes/origin/main \
                refs/tags/mark \
                refs/tags/mark1.1 \
                refs/tags/mark1.10 \
-               refs/tags/mark1.2 >>expect &&
-       # Protocol v2 supports sending symrefs for refs other than HEAD, so use
-       # protocol v0 here.
-       GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref >actual &&
-       test_cmp expect actual
+               refs/tags/mark1.2 >>expect.v2 &&
+       # v0 does not show non-HEAD symrefs
+       grep -v "ref: refs/remotes" <expect.v2 >expect.v0 &&
+       git -c protocol.version=0 ls-remote --symref >actual.v0 &&
+       test_cmp expect.v0 actual.v0 &&
+       git -c protocol.version=2 ls-remote --symref >actual.v2 &&
+       test_cmp expect.v2 actual.v2
 '
 
 test_expect_success 'ls-remote with filtered symref (refname)' '
@@ -255,76 +271,41 @@ test_expect_success 'ls-remote with filtered symref (refname)' '
        ref: refs/heads/main    HEAD
        $rev    HEAD
        EOF
-       # Protocol v2 supports sending symrefs for refs other than HEAD, so use
-       # protocol v0 here.
-       GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . HEAD >actual &&
+       git ls-remote --symref . HEAD >actual &&
        test_cmp expect actual
 '
 
-test_expect_failure 'ls-remote with filtered symref (--heads)' '
+test_expect_success 'ls-remote with filtered symref (--heads)' '
        git symbolic-ref refs/heads/foo refs/tags/mark &&
-       cat >expect <<-EOF &&
+       cat >expect.v2 <<-EOF &&
        ref: refs/tags/mark     refs/heads/foo
        $rev    refs/heads/foo
        $rev    refs/heads/main
        EOF
-       # Protocol v2 supports sending symrefs for refs other than HEAD, so use
-       # protocol v0 here.
-       GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual &&
-       test_cmp expect actual
+       grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 &&
+       git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 &&
+       test_cmp expect.v0 actual.v0 &&
+       git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 &&
+       test_cmp expect.v2 actual.v2
 '
 
-test_expect_success 'ls-remote --symref omits filtered-out matches' '
-       cat >expect <<-EOF &&
-       $rev    refs/heads/foo
-       $rev    refs/heads/main
+test_expect_success 'indicate no refs in v0 standards-compliant empty remote' '
+       # Git does not produce an output like this, but it does match the
+       # standard and is produced by other implementations like JGit. So
+       # hard-code the case we care about.
+       #
+       # The actual capabilities do not matter; there are none that would
+       # change how ls-remote behaves.
+       oid=0000000000000000000000000000000000000000 &&
+       test-tool pkt-line pack >input.q <<-EOF &&
+       $oid capabilities^{}Qcaps-go-here
+       0000
        EOF
-       # Protocol v2 supports sending symrefs for refs other than HEAD, so use
-       # protocol v0 here.
-       GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual &&
-       test_cmp expect actual &&
-       GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . "refs/heads/*" >actual &&
-       test_cmp expect actual
-'
-
-test_lazy_prereq GIT_DAEMON '
-       test_bool_env GIT_TEST_GIT_DAEMON true
-'
+       q_to_nul <input.q >input &&
 
-# This test spawns a daemon, so run it only if the user would be OK with
-# testing with git-daemon.
-test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' '
-       test_set_port JGIT_DAEMON_PORT &&
-       JGIT_DAEMON_PID= &&
-       git init --bare empty.git &&
-       >empty.git/git-daemon-export-ok &&
-       mkfifo jgit_daemon_output &&
-       {
-               jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output &
-               JGIT_DAEMON_PID=$!
-       } &&
-       test_when_finished kill "$JGIT_DAEMON_PID" &&
-       {
-               read line &&
-               case $line in
-               Exporting*)
-                       ;;
-               *)
-                       echo "Expected: Exporting" &&
-                       false;;
-               esac &&
-               read line &&
-               case $line in
-               "Listening on"*)
-                       ;;
-               *)
-                       echo "Expected: Listening on" &&
-                       false;;
-               esac
-       } <jgit_daemon_output &&
        # --exit-code asks the command to exit with 2 when no
        # matching refs are found.
-       test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
+       test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input .
 '
 
 test_expect_success 'ls-remote works outside repository' '
@@ -345,8 +326,8 @@ test_expect_success 'ls-remote --sort fails gracefully outside repository' '
 test_expect_success 'ls-remote patterns work with all protocol versions' '
        git for-each-ref --format="%(objectname)        %(refname)" \
                refs/heads/main refs/remotes/origin/main >expect &&
-       git -c protocol.version=1 ls-remote . main >actual.v1 &&
-       test_cmp expect actual.v1 &&
+       git -c protocol.version=0 ls-remote . main >actual.v0 &&
+       test_cmp expect actual.v0 &&
        git -c protocol.version=2 ls-remote . main >actual.v2 &&
        test_cmp expect actual.v2
 '
@@ -354,10 +335,49 @@ test_expect_success 'ls-remote patterns work with all protocol versions' '
 test_expect_success 'ls-remote prefixes work with all protocol versions' '
        git for-each-ref --format="%(objectname)        %(refname)" \
                refs/heads/ refs/tags/ >expect &&
-       git -c protocol.version=1 ls-remote --heads --tags . >actual.v1 &&
-       test_cmp expect actual.v1 &&
+       git -c protocol.version=0 ls-remote --heads --tags . >actual.v0 &&
+       test_cmp expect actual.v0 &&
        git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 &&
        test_cmp expect actual.v2
 '
 
+test_expect_success 'v0 clients can handle multiple symrefs' '
+       # Modern versions of Git will not return multiple symref capabilities
+       # for v0, so we have to hard-code the response. Note that we will
+       # always use both v0 and object-format=sha1 here, as the hard-coded
+       # response reflects a server that only supports those.
+       oid=1234567890123456789012345678901234567890 &&
+       symrefs="symref=refs/remotes/origin/HEAD:refs/remotes/origin/main" &&
+       symrefs="$symrefs symref=HEAD:refs/heads/main" &&
+
+       # Likewise we want to make sure our parser is not fooled by the string
+       # "symref" appearing as part of an earlier cap. But there is no way to
+       # do that via upload-pack, as arbitrary strings can appear only in a
+       # "symref" value itself (where we skip past the values as a whole)
+       # and "agent" (which always appears after "symref", so putting our
+       # parser in a confused state is less interesting).
+       caps="some other caps including a-fake-symref-cap" &&
+
+       test-tool pkt-line pack >input.q <<-EOF &&
+       $oid HEADQ$caps $symrefs
+       $oid refs/heads/main
+       $oid refs/remotes/origin/HEAD
+       $oid refs/remotes/origin/main
+       0000
+       EOF
+       q_to_nul <input.q >input &&
+
+       cat >expect <<-EOF &&
+       ref: refs/heads/main    HEAD
+       $oid    HEAD
+       $oid    refs/heads/main
+       ref: refs/remotes/origin/main   refs/remotes/origin/HEAD
+       $oid    refs/remotes/origin/HEAD
+       $oid    refs/remotes/origin/main
+       EOF
+
+       git ls-remote --symref --upload-pack=./cat-input . >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 54f422ced3241870a40da6714c34564abab7c119..98f034aa77bb243492ea1232549f7d1ec195a152 100755 (executable)
@@ -58,6 +58,13 @@ test_expect_success 'git fetch --all' '
         test_cmp expect output)
 '
 
+test_expect_success 'git fetch --all --no-write-fetch-head' '
+       (cd test &&
+       rm -f .git/FETCH_HEAD &&
+       git fetch --all --no-write-fetch-head &&
+       test_path_is_missing .git/FETCH_HEAD)
+'
+
 test_expect_success 'git fetch --all should continue if a remote has errors' '
        (git clone one test2 &&
         cd test2 &&
index 98a27a2948b5f6c1b1c318b43c5fab3505f1426e..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 &&
        (
@@ -401,6 +412,11 @@ test_expect_success 'push with ambiguity' '
 
 '
 
+test_expect_success 'push with onelevel ref' '
+       mk_test testrepo heads/main &&
+       test_must_fail git push testrepo HEAD:refs/onelevel
+'
+
 test_expect_success 'push with colon-less refspec (1)' '
 
        mk_test testrepo heads/frotz tags/frotz &&
@@ -898,6 +914,13 @@ test_expect_success 'push --delete refuses empty string' '
        test_must_fail git push testrepo --delete ""
 '
 
+test_expect_success 'push --delete onelevel refspecs' '
+       mk_test testrepo heads/main &&
+       git -C testrepo update-ref refs/onelevel refs/heads/main &&
+       git push testrepo --delete refs/onelevel &&
+       test_must_fail git -C testrepo rev-parse --verify refs/onelevel
+'
+
 test_expect_success 'warn on push to HEAD of non-bare repository' '
        mk_test testrepo heads/main &&
        (
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 394bc60cb8eea153e534b9fc887ae37b0e2abf36..cc5496e28fd0bcbf32badb583272c464ec88fae8 100755 (executable)
@@ -79,7 +79,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' '
                git commit -m push ./file &&
                git push
        ) &&
-       test push = $(git show HEAD:subdir/file)
+       echo push >expect &&
+       git show HEAD:subdir/file >actual &&
+       test_cmp expect actual
 '
 
 test_done
index c9acc076353a6ae784ced36a4927cda352950521..1b8d609879504daa09bd62826f223e7eb55bf0d5 100755 (executable)
@@ -61,12 +61,20 @@ test_expect_success 'push -u :topic_2' '
        check_config topic_2 upstream refs/heads/other2
 '
 
-test_expect_success 'push -u --all' '
+test_expect_success 'push -u --all(the same behavior with--branches)' '
        git branch all1 &&
        git branch all2 &&
        git push -u --all &&
        check_config all1 upstream refs/heads/all1 &&
-       check_config all2 upstream refs/heads/all2
+       check_config all2 upstream refs/heads/all2 &&
+       git config --get-regexp branch.all* > expect &&
+       git config --remove-section branch.all1 &&
+       git config --remove-section branch.all2 &&
+       git push -u --branches &&
+       check_config all1 upstream refs/heads/all1 &&
+       check_config all2 upstream refs/heads/all2 &&
+       git config --get-regexp branch.all* > actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'push -u HEAD' '
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 b9546ef8e5e5cd3a734228c4d65ffdb59f568684..26e933f93ae7f72261046495f25f63af8c31349d 100755 (executable)
@@ -167,6 +167,19 @@ test_expect_success "fetch --recurse-submodules recurses into submodules" '
        verify_fetch_result actual.err
 '
 
+test_expect_success "fetch --recurse-submodules honors --no-write-fetch-head" '
+       (
+               cd downstream &&
+               git submodule foreach --recursive \
+               sh -c "cd \"\$(git rev-parse --git-dir)\" && rm -f FETCH_HEAD" &&
+
+               git fetch --recurse-submodules --no-write-fetch-head &&
+
+               git submodule foreach --recursive \
+               sh -c "cd \"\$(git rev-parse --git-dir)\" && ! test -f FETCH_HEAD"
+       )
+'
+
 test_expect_success "submodule.recurse option triggers recursive fetch" '
        add_submodule_commits &&
        (
@@ -1167,4 +1180,17 @@ test_expect_success 'fetch --all with --recurse-submodules with multiple' '
        test_line_count = 2 fetch-subs
 '
 
+test_expect_success "fetch --all with --no-recurse-submodules only fetches superproject" '
+       test_when_finished "rm -rf src_clone" &&
+
+       git clone --recurse-submodules src src_clone &&
+       (
+               cd src_clone &&
+               git remote add secondary ../src &&
+               git config submodule.recurse true &&
+               git fetch --all --no-recurse-submodules 2>../fetch-log
+       ) &&
+       ! grep "Fetching submodule" fetch-log
+'
+
 test_done
index 70431122a40360c265dc28627c4208dc360c000c..04b47ad84a86ab3407ba26f069d934ed7dcb5dec 100755 (executable)
@@ -117,7 +117,10 @@ test_expect_success 'atomic push fails if one branch fails' '
                test_commit five &&
                git checkout main &&
                test_commit six &&
-               test_must_fail git push --atomic --all up
+               test_must_fail git push --atomic --all up >output-all 2>&1 &&
+               # --all and --branches have the same behavior when be combined with --atomic
+               test_must_fail git push --atomic --branches up >output-branches 2>&1 &&
+               test_cmp output-all output-branches
        ) &&
        test_refs main HEAD@{7} &&
        test_refs second HEAD@{4}
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 0908534f2561f4bc68319f4dc4ffc464ba4e4a90..21b7767cbd313b48a13888c28f5e757e59b394db 100755 (executable)
@@ -611,6 +611,33 @@ test_expect_success 'client falls back from v2 to v0 to match server' '
        grep symref=HEAD:refs/heads/ trace
 '
 
+test_expect_success 'create empty http-accessible SHA-256 repository' '
+       mkdir "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" &&
+       (cd "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" &&
+        git --bare init --object-format=sha256
+       )
+'
+
+test_expect_success 'clone empty SHA-256 repository with protocol v2' '
+       rm -fr sha256 &&
+       echo sha256 >expected &&
+       git -c protocol.version=2 clone "$HTTPD_URL/smart/sha256.git" &&
+       git -C sha256 rev-parse --show-object-format >actual &&
+       test_cmp actual expected &&
+       git ls-remote "$HTTPD_URL/smart/sha256.git" >actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success 'clone empty SHA-256 repository with protocol v0' '
+       rm -fr sha256 &&
+       echo sha256 >expected &&
+       GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=0 clone "$HTTPD_URL/smart/sha256.git" &&
+       git -C sha256 rev-parse --show-object-format >actual &&
+       test_cmp actual expected &&
+       git ls-remote "$HTTPD_URL/smart/sha256.git" >actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'passing hostname resolution information works' '
        BOGUS_HOST=gitbogusexamplehost.invalid &&
        BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT &&
index 165427d57e5cfb2c4ecd3826564bf7ea89fba629..b55a9f65e6bfb56b0461ca6b6da0ec03df2cda32 100755 (executable)
@@ -3,6 +3,22 @@
 test_description='test skipping fetch negotiator'
 . ./test-lib.sh
 
+test_expect_success 'fetch.negotiationalgorithm config' '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       cat >repo/.git/config <<-\EOF &&
+       [fetch]
+       negotiationAlgorithm
+       EOF
+       cat >expect <<-\EOF &&
+       error: missing value for '\''fetch.negotiationalgorithm'\''
+       fatal: bad config variable '\''fetch.negotiationalgorithm'\'' in file '\''.git/config'\'' at line 2
+       EOF
+       test_expect_code 128 git -C repo fetch >out 2>actual &&
+       test_must_be_empty out &&
+       test_cmp expect actual
+'
+
 have_sent () {
        while test "$#" -ne 0
        do
index afd56926c5371b90eaf42d5823541f6f93788ba1..996a08e90c9c2c5b2c37405b1b3082e82d29a7e8 100755 (executable)
@@ -1018,6 +1018,40 @@ test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
        test_cmp expect refs
 '
 
+test_expect_success 'bundles are downloaded once during fetch --all' '
+       test_when_finished rm -rf download-* trace*.txt fetch-mult &&
+
+       cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+       [bundle]
+               version = 1
+               mode = all
+               heuristic = creationToken
+
+       [bundle "bundle-1"]
+               uri = bundle-1.bundle
+               creationToken = 1
+
+       [bundle "bundle-2"]
+               uri = bundle-2.bundle
+               creationToken = 2
+
+       [bundle "bundle-3"]
+               uri = bundle-3.bundle
+               creationToken = 3
+       EOF
+
+       git clone --single-branch --branch=left \
+               --bundle-uri="$HTTPD_URL/bundle-list" \
+               "$HTTPD_URL/smart/fetch.git" fetch-mult &&
+       git -C fetch-mult remote add dup1 "$HTTPD_URL/smart/fetch.git" &&
+       git -C fetch-mult remote add dup2 "$HTTPD_URL/smart/fetch.git" &&
+
+       GIT_TRACE2_EVENT="$(pwd)/trace-mult.txt" \
+               git -C fetch-mult fetch --all &&
+       grep "\"child_start\".*\"git-remote-https\",\"$HTTPD_URL/bundle-list\"" \
+               trace-mult.txt >bundle-fetches &&
+       test_line_count = 1 bundle-fetches
+'
 # Do not add tests here unless they use the HTTP server, as they will
 # not run unless the HTTP dependencies exist.
 
diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh
new file mode 100755 (executable)
index 0000000..ab8a721
--- /dev/null
@@ -0,0 +1,329 @@
+#!/bin/sh
+
+test_description='test http auth header and credential helper interop'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+
+enable_cgipassauth
+if ! test_have_prereq CGIPASSAUTH
+then
+       skip_all="no CGIPassAuth support"
+       test_done
+fi
+start_httpd
+
+test_expect_success 'setup_credential_helper' '
+       mkdir "$TRASH_DIRECTORY/bin" &&
+       PATH=$PATH:"$TRASH_DIRECTORY/bin" &&
+       export PATH &&
+
+       CREDENTIAL_HELPER="$TRASH_DIRECTORY/bin/git-credential-test-helper" &&
+       write_script "$CREDENTIAL_HELPER" <<-\EOF
+       cmd=$1
+       teefile=$cmd-query.cred
+       catfile=$cmd-reply.cred
+       sed -n -e "/^$/q" -e "p" >>$teefile
+       if test "$cmd" = "get"
+       then
+               cat $catfile
+       fi
+       EOF
+'
+
+set_credential_reply () {
+       cat >"$TRASH_DIRECTORY/$1-reply.cred"
+}
+
+expect_credential_query () {
+       cat >"$TRASH_DIRECTORY/$1-expect.cred" &&
+       test_cmp "$TRASH_DIRECTORY/$1-expect.cred" \
+                "$TRASH_DIRECTORY/$1-query.cred"
+}
+
+per_test_cleanup () {
+       rm -f *.cred &&
+       rm -f "$HTTPD_ROOT_PATH"/custom-auth.valid \
+             "$HTTPD_ROOT_PATH"/custom-auth.challenge
+}
+
+test_expect_success 'setup repository' '
+       test_commit foo &&
+       git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+       git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"
+'
+
+test_expect_success 'access using basic auth' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=alice
+       password=secret-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+       WWW-Authenticate: Basic realm="example.com"
+       EOF
+
+       test_config_global credential.helper test-helper &&
+       git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=Basic realm="example.com"
+       EOF
+
+       expect_credential_query store <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=alice
+       password=secret-passwd
+       EOF
+'
+
+test_expect_success 'access using basic auth invalid credentials' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=baduser
+       password=wrong-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+       WWW-Authenticate: Basic realm="example.com"
+       EOF
+
+       test_config_global credential.helper test-helper &&
+       test_must_fail git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=Basic realm="example.com"
+       EOF
+
+       expect_credential_query erase <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=baduser
+       password=wrong-passwd
+       wwwauth[]=Basic realm="example.com"
+       EOF
+'
+
+test_expect_success 'access using basic auth with extra challenges' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=alice
+       password=secret-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+       WWW-Authenticate: FooBar param1="value1" param2="value2"
+       WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+       WWW-Authenticate: Basic realm="example.com"
+       EOF
+
+       test_config_global credential.helper test-helper &&
+       git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=FooBar param1="value1" param2="value2"
+       wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+       wwwauth[]=Basic realm="example.com"
+       EOF
+
+       expect_credential_query store <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=alice
+       password=secret-passwd
+       EOF
+'
+
+test_expect_success 'access using basic auth mixed-case wwwauth header name' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=alice
+       password=secret-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+       www-authenticate: foobar param1="value1" param2="value2"
+       WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0
+       WwW-aUtHeNtIcAtE: baSiC realm="example.com"
+       EOF
+
+       test_config_global credential.helper test-helper &&
+       git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=foobar param1="value1" param2="value2"
+       wwwauth[]=BEARER authorize_uri="id.example.com" p=1 q=0
+       wwwauth[]=baSiC realm="example.com"
+       EOF
+
+       expect_credential_query store <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=alice
+       password=secret-passwd
+       EOF
+'
+
+test_expect_success 'access using basic auth with wwwauth header continuations' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=alice
+       password=secret-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       # Note that leading and trailing whitespace is important to correctly
+       # simulate a continuation/folded header.
+       cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+       WWW-Authenticate: FooBar param1="value1"
+        param2="value2"
+       WWW-Authenticate: Bearer authorize_uri="id.example.com"
+        p=1
+        q=0
+       WWW-Authenticate: Basic realm="example.com"
+       EOF
+
+       test_config_global credential.helper test-helper &&
+       git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=FooBar param1="value1" param2="value2"
+       wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+       wwwauth[]=Basic realm="example.com"
+       EOF
+
+       expect_credential_query store <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=alice
+       password=secret-passwd
+       EOF
+'
+
+test_expect_success 'access using basic auth with wwwauth header empty continuations' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=alice
+       password=secret-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+       # Note that leading and trailing whitespace is important to correctly
+       # simulate a continuation/folded header.
+       printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" &&
+       printf " \r\n" >>"$CHALLENGE" &&
+       printf " param2=\"value2\"\r\n" >>"$CHALLENGE" &&
+       printf "WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" &&
+       printf " p=1\r\n" >>"$CHALLENGE" &&
+       printf " \r\n" >>"$CHALLENGE" &&
+       printf " q=0\r\n" >>"$CHALLENGE" &&
+       printf "WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" &&
+
+       test_config_global credential.helper test-helper &&
+       git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=FooBar param1="value1" param2="value2"
+       wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+       wwwauth[]=Basic realm="example.com"
+       EOF
+
+       expect_credential_query store <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=alice
+       password=secret-passwd
+       EOF
+'
+
+test_expect_success 'access using basic auth with wwwauth header mixed line-endings' '
+       test_when_finished "per_test_cleanup" &&
+
+       set_credential_reply get <<-EOF &&
+       username=alice
+       password=secret-passwd
+       EOF
+
+       # Basic base64(alice:secret-passwd)
+       cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+       Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+       EOF
+
+       CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+       # Note that leading and trailing whitespace is important to correctly
+       # simulate a continuation/folded header.
+       printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" &&
+       printf " \r\n" >>"$CHALLENGE" &&
+       printf "\tparam2=\"value2\"\r\n" >>"$CHALLENGE" &&
+       printf "WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" &&
+
+       test_config_global credential.helper test-helper &&
+       git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+       expect_credential_query get <<-EOF &&
+       protocol=http
+       host=$HTTPD_DEST
+       wwwauth[]=FooBar param1="value1" param2="value2"
+       wwwauth[]=Basic realm="example.com"
+       EOF
+
+       expect_credential_query store <<-EOF
+       protocol=http
+       host=$HTTPD_DEST
+       username=alice
+       password=secret-passwd
+       EOF
+'
+
+test_done
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 09097eff3f46033a26c9b60c94bb8cb79f3fad2c..4e917bf87d2d4213019797ffa4d12215ffeb05f5 100755 (executable)
@@ -121,7 +121,7 @@ test_expect_success "fetch.recurseSubmodules option triggers recursive fetch (bu
        sub_oid=$(git -C child rev-parse HEAD) &&
        git -C super/sub cat-file -e $sub_oid &&
        # Check that the submodule worktree did not update
-       ! test_path_is_file super/sub/merge_strategy_5.t
+       test_path_is_missing super/sub/merge_strategy_5.t
 '
 
 test_expect_success "fetch.recurseSubmodules takes precedence over submodule.recurse" '
@@ -134,7 +134,7 @@ test_expect_success "fetch.recurseSubmodules takes precedence over submodule.rec
        sub_oid=$(git -C child rev-parse HEAD) &&
        git -C super/sub cat-file -e $sub_oid &&
        # Check that the submodule worktree did not update
-       ! test_path_is_file super/sub/merge_strategy_6.t
+       test_path_is_missing super/sub/merge_strategy_6.t
 '
 
 test_expect_success 'pull --rebase --recurse-submodules (remote superproject submodule changes, local submodule changes)' '
diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh
new file mode 100755 (executable)
index 0000000..90e6dcb
--- /dev/null
@@ -0,0 +1,293 @@
+#!/bin/sh
+
+test_description='git fetch output format'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'fetch with invalid output format configuration' '
+       test_when_finished "rm -rf clone" &&
+       git clone . clone &&
+
+       test_must_fail git -C clone -c fetch.output fetch origin 2>actual.err &&
+       cat >expect <<-EOF &&
+       error: missing value for ${SQ}fetch.output${SQ}
+       fatal: unable to parse ${SQ}fetch.output${SQ} from command-line config
+       EOF
+       test_cmp expect actual.err &&
+
+       test_must_fail git -C clone -c fetch.output= fetch origin 2>actual.err &&
+       cat >expect <<-EOF &&
+       fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}${SQ}
+       EOF
+       test_cmp expect actual.err &&
+
+       test_must_fail git -C clone -c fetch.output=garbage fetch origin 2>actual.err &&
+       cat >expect <<-EOF &&
+       fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}garbage${SQ}
+       EOF
+       test_cmp expect actual.err
+'
+
+test_expect_success 'fetch aligned output' '
+       git clone . full-output &&
+       test_commit looooooooooooong-tag &&
+       (
+               cd full-output &&
+               git -c fetch.output=full fetch origin >actual 2>&1 &&
+               grep -e "->" actual | cut -c 22- >../actual
+       ) &&
+       cat >expect <<-\EOF &&
+       main                 -> origin/main
+       looooooooooooong-tag -> looooooooooooong-tag
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'fetch compact output' '
+       git clone . compact &&
+       test_commit extraaa &&
+       (
+               cd compact &&
+               git -c fetch.output=compact fetch origin >actual 2>&1 &&
+               grep -e "->" actual | cut -c 22- >../actual
+       ) &&
+       cat >expect <<-\EOF &&
+       main       -> origin/*
+       extraaa    -> *
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'fetch porcelain output' '
+       test_when_finished "rm -rf porcelain" &&
+
+       # Set up a bunch of references that we can use to demonstrate different
+       # kinds of flag symbols in the output format.
+       MAIN_OLD=$(git rev-parse HEAD) &&
+       git branch "fast-forward" &&
+       git branch "deleted-branch" &&
+       git checkout -b force-updated &&
+       test_commit --no-tag force-update-old &&
+       FORCE_UPDATED_OLD=$(git rev-parse HEAD) &&
+       git checkout main &&
+
+       # Clone and pre-seed the repositories. We fetch references into two
+       # namespaces so that we can test that rejected and force-updated
+       # references are reported properly.
+       refspecs="refs/heads/*:refs/unforced/* +refs/heads/*:refs/forced/*" &&
+       git clone . porcelain &&
+       git -C porcelain fetch origin $refspecs &&
+
+       # Now that we have set up the client repositories we can change our
+       # local references.
+       git branch new-branch &&
+       git branch -d deleted-branch &&
+       git checkout fast-forward &&
+       test_commit --no-tag fast-forward-new &&
+       FAST_FORWARD_NEW=$(git rev-parse HEAD) &&
+       git checkout force-updated &&
+       git reset --hard HEAD~ &&
+       test_commit --no-tag force-update-new &&
+       FORCE_UPDATED_NEW=$(git rev-parse HEAD) &&
+
+       cat >expect <<-EOF &&
+       - $MAIN_OLD $ZERO_OID refs/forced/deleted-branch
+       - $MAIN_OLD $ZERO_OID refs/unforced/deleted-branch
+         $MAIN_OLD $FAST_FORWARD_NEW refs/unforced/fast-forward
+       ! $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/unforced/force-updated
+       * $ZERO_OID $MAIN_OLD refs/unforced/new-branch
+         $MAIN_OLD $FAST_FORWARD_NEW refs/forced/fast-forward
+       + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/forced/force-updated
+       * $ZERO_OID $MAIN_OLD refs/forced/new-branch
+         $MAIN_OLD $FAST_FORWARD_NEW refs/remotes/origin/fast-forward
+       + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/remotes/origin/force-updated
+       * $ZERO_OID $MAIN_OLD refs/remotes/origin/new-branch
+       EOF
+
+       # Execute a dry-run fetch first. We do this to assert that the dry-run
+       # and non-dry-run fetches produces the same output. Execution of the
+       # fetch is expected to fail as we have a rejected reference update.
+       test_must_fail git -C porcelain fetch \
+               --porcelain --dry-run --prune origin $refspecs >actual &&
+       test_cmp expect actual &&
+
+       # And now we perform a non-dry-run fetch.
+       test_must_fail git -C porcelain fetch \
+               --porcelain --prune origin $refspecs >actual 2>stderr &&
+       test_cmp expect actual &&
+       test_must_be_empty stderr
+'
+
+test_expect_success 'fetch porcelain with multiple remotes' '
+       test_when_finished "rm -rf porcelain" &&
+
+       git switch --create multiple-remotes &&
+       git clone . porcelain &&
+       git -C porcelain remote add second-remote "$PWD" &&
+       git -C porcelain fetch second-remote &&
+
+       test_commit --no-tag multi-commit &&
+       old_commit=$(git rev-parse HEAD~) &&
+       new_commit=$(git rev-parse HEAD) &&
+
+       cat >expect <<-EOF &&
+         $old_commit $new_commit refs/remotes/origin/multiple-remotes
+         $old_commit $new_commit refs/remotes/second-remote/multiple-remotes
+       EOF
+
+       git -C porcelain fetch --porcelain --all >actual 2>stderr &&
+       test_cmp expect actual &&
+       test_must_be_empty stderr
+'
+
+test_expect_success 'fetch porcelain refuses to work with submodules' '
+       test_when_finished "rm -rf porcelain" &&
+
+       cat >expect <<-EOF &&
+       fatal: options ${SQ}--porcelain${SQ} and ${SQ}--recurse-submodules${SQ} cannot be used together
+       EOF
+
+       git init porcelain &&
+       test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=yes 2>stderr &&
+       test_cmp expect stderr &&
+
+       test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=on-demand 2>stderr &&
+       test_cmp expect stderr
+'
+
+test_expect_success 'fetch porcelain overrides fetch.output config' '
+       test_when_finished "rm -rf porcelain" &&
+
+       git switch --create config-override &&
+       git clone . porcelain &&
+       test_commit new-commit &&
+       old_commit=$(git rev-parse HEAD~) &&
+       new_commit=$(git rev-parse HEAD) &&
+
+       cat >expect <<-EOF &&
+         $old_commit $new_commit refs/remotes/origin/config-override
+       * $ZERO_OID $new_commit refs/tags/new-commit
+       EOF
+
+       git -C porcelain -c fetch.output=compact fetch --porcelain >stdout 2>stderr &&
+       test_must_be_empty stderr &&
+       test_cmp expect stdout
+'
+
+test_expect_success 'fetch --no-porcelain overrides previous --porcelain' '
+       test_when_finished "rm -rf no-porcelain" &&
+
+       git switch --create no-porcelain &&
+       git clone . no-porcelain &&
+       test_commit --no-tag no-porcelain &&
+       old_commit=$(git rev-parse --short HEAD~) &&
+       new_commit=$(git rev-parse --short HEAD) &&
+
+       cat >expect <<-EOF &&
+       From $(test-tool path-utils real_path .)/.
+          $old_commit..$new_commit  no-porcelain -> origin/no-porcelain
+       EOF
+
+       git -C no-porcelain fetch --porcelain --no-porcelain >stdout 2>stderr &&
+       test_cmp expect stderr &&
+       test_must_be_empty stdout
+'
+
+test_expect_success 'fetch output with HEAD' '
+       test_when_finished "rm -rf head" &&
+       git clone . head &&
+
+       git -C head fetch --dry-run origin HEAD >actual.out 2>actual.err &&
+       cat >expect <<-EOF &&
+       From $(test-tool path-utils real_path .)/.
+        * branch            HEAD       -> FETCH_HEAD
+       EOF
+       test_must_be_empty actual.out &&
+       test_cmp expect actual.err &&
+
+       git -C head fetch origin HEAD >actual.out 2>actual.err &&
+       test_must_be_empty actual.out &&
+       test_cmp expect actual.err &&
+
+       git -C head fetch --dry-run origin HEAD:foo >actual.out 2>actual.err &&
+       cat >expect <<-EOF &&
+       From $(test-tool path-utils real_path .)/.
+        * [new ref]         HEAD       -> foo
+       EOF
+       test_must_be_empty actual.out &&
+       test_cmp expect actual.err &&
+
+       git -C head fetch origin HEAD:foo >actual.out 2>actual.err &&
+       test_must_be_empty actual.out &&
+       test_cmp expect actual.err
+'
+
+test_expect_success 'fetch porcelain output with HEAD' '
+       test_when_finished "rm -rf head" &&
+       git clone . head &&
+       COMMIT_ID=$(git rev-parse HEAD) &&
+
+       git -C head fetch --porcelain --dry-run origin HEAD >actual &&
+       cat >expect <<-EOF &&
+       * $ZERO_OID $COMMIT_ID FETCH_HEAD
+       EOF
+       test_cmp expect actual &&
+
+       git -C head fetch --porcelain origin HEAD >actual &&
+       test_cmp expect actual &&
+
+       git -C head fetch --porcelain --dry-run origin HEAD:foo >actual &&
+       cat >expect <<-EOF &&
+       * $ZERO_OID $COMMIT_ID refs/heads/foo
+       EOF
+       test_cmp expect actual &&
+
+       git -C head fetch --porcelain origin HEAD:foo >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'fetch output with object ID' '
+       test_when_finished "rm -rf object-id" &&
+       git clone . object-id &&
+       commit=$(git rev-parse HEAD) &&
+
+       git -C object-id fetch --dry-run origin $commit:object-id >actual.out 2>actual.err &&
+       cat >expect <<-EOF &&
+       From $(test-tool path-utils real_path .)/.
+        * [new ref]         $commit -> object-id
+       EOF
+       test_must_be_empty actual.out &&
+       test_cmp expect actual.err &&
+
+       git -C object-id fetch origin $commit:object-id >actual.out 2>actual.err &&
+       test_must_be_empty actual.out &&
+       test_cmp expect actual.err
+'
+
+test_expect_success '--no-show-forced-updates' '
+       mkdir forced-updates &&
+       (
+               cd forced-updates &&
+               git init &&
+               test_commit 1 &&
+               test_commit 2
+       ) &&
+       git clone forced-updates forced-update-clone &&
+       git clone forced-updates no-forced-update-clone &&
+       git -C forced-updates reset --hard HEAD~1 &&
+       (
+               cd forced-update-clone &&
+               git fetch --show-forced-updates origin 2>output &&
+               test_i18ngrep "(forced update)" output
+       ) &&
+       (
+               cd no-forced-update-clone &&
+               git fetch --no-show-forced-updates origin 2>output &&
+               test_i18ngrep ! "(forced update)" output
+       )
+'
+
+test_done
diff --git a/t/t5583-push-branches.sh b/t/t5583-push-branches.sh
new file mode 100755 (executable)
index 0000000..320f49c
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+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() {
+       dir=$1
+       shift
+       rm -rf deletes
+       for arg in $*
+       do
+               echo "delete ${arg}" >>deletes
+       done
+       git -C $dir update-ref --stdin < deletes
+}
+
+test_expect_success 'setup bare remote' '
+       git init --bare remote-1 &&
+       git -C remote-1 config gc.auto 0 &&
+       test_commit one &&
+       git push remote-1 HEAD
+'
+
+test_expect_success 'setup different types of references' '
+       cat >refs <<-EOF &&
+       update refs/heads/branch-1 HEAD
+       update refs/heads/branch-2 HEAD
+       EOF
+
+       git tag -a -m "annotated" annotated-1 HEAD &&
+       git tag -a -m "annotated" annotated-2 HEAD &&
+       git update-ref --stdin < refs
+'
+
+test_expect_success '--all and --branches have the same behavior' '
+       test_when_finished "delete_refs remote-1 \
+                          refs/heads/branch-1 \
+                          refs/heads/branch-2" &&
+       git push remote-1 --all &&
+       commit=$(git rev-parse HEAD) &&
+       cat >expect <<-EOF &&
+       $commit refs/heads/branch-1
+       $commit refs/heads/branch-2
+       $commit refs/heads/main
+       EOF
+
+       git -C remote-1 show-ref --heads >actual.all &&
+       delete_refs remote-1 refs/heads/branch-1 refs/heads/branch-2 &&
+       git push remote-1 --branches &&
+       git -C remote-1 show-ref --heads >actual.branches &&
+       test_cmp actual.all actual.branches &&
+       test_cmp expect actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with refspecs' '
+       test_must_fail git push remote-1 --all main >actual.all 2>&1 &&
+       test_must_fail git push remote-1 --branches main >actual.branches 2>&1 &&
+       test_cmp actual.all actual.branches &&
+       grep "be combined with refspecs" actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with --mirror' '
+       test_must_fail git push remote-1 --all --mirror >actual.all 2>&1 &&
+       test_must_fail git push remote-1 --branches --mirror >actual.branches 2>&1 &&
+       test_cmp actual.all actual.branches &&
+       grep "cannot be used together" actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with --tags' '
+       test_must_fail git push remote-1 --all --tags >actual.all 2>&1 &&
+       test_must_fail git push remote-1 --branches --tags >actual.branches 2>&1 &&
+       test_cmp actual.all actual.branches &&
+       grep "cannot be used together" actual.all
+'
+
+
+test_expect_success '--all or --branches can not be combined with --delete' '
+       test_must_fail git push remote-1 --all --delete >actual.all 2>&1 &&
+       test_must_fail git push remote-1 --branches --delete >actual.branches 2>&1 &&
+       test_cmp actual.all actual.branches &&
+       grep "cannot be used together" actual.all
+'
+
+test_expect_success '--all or --branches combines with --follow-tags have same behavior' '
+       test_when_finished "delete_refs remote-1 \
+                          refs/heads/branch-1 \
+                          refs/heads/branch-2 \
+                          refs/tags/annotated-1 \
+                          refs/tags/annotated-2" &&
+       git push remote-1 --all --follow-tags &&
+       git -C remote-1 show-ref > actual.all &&
+       cat >expect <<-EOF &&
+       $commit refs/heads/branch-1
+       $commit refs/heads/branch-2
+       $commit refs/heads/main
+       $(git rev-parse annotated-1) refs/tags/annotated-1
+       $(git rev-parse annotated-2) refs/tags/annotated-2
+       EOF
+
+       delete_refs remote-1 \
+                   refs/heads/branch-1 \
+                   refs/heads/branch-2 \
+                   refs/tags/annotated-1 \
+                   refs/tags/annotated-2 &&
+       git push remote-1 --branches --follow-tags &&
+       git -C remote-1 show-ref >actual.branches &&
+       test_cmp actual.all actual.branches &&
+       test_cmp expect actual.all
+'
+
+test_done
index 83e3c97861ddc50eb9e6b1a78e68d693224c3fc9..9845fc04d59809acc17dbe7c8a122c93b84d4f75 100755 (executable)
@@ -358,7 +358,7 @@ test_expect_success SYMLINKS 'clone repo with symlinked objects directory' '
        test_must_fail git clone --local malicious clone 2>err &&
 
        test_path_is_missing clone &&
-       grep "failed to start iterator over" err
+       grep "is a symlink, refusing to clone with --local" err
 '
 
 test_done
index 38b850c10ef8cddeb790ed276209bb5019439eae..1d7b1abda1a4870971efb8408c11a4dde2e7564e 100755 (executable)
@@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' '
        : >file && git add . && git commit -m1 &&
        git clone --bare . a.git &&
        git clone --bare . x &&
-       test "$(cd a.git && git config --bool core.bare)" = true &&
-       test "$(cd x && git config --bool core.bare)" = true &&
+       echo true >expect &&
+       git -C a.git config --bool core.bare >actual &&
+       test_cmp expect actual &&
+       echo true >expect &&
+       git -C x config --bool core.bare >actual &&
+       test_cmp expect actual &&
        git bundle create b1.bundle --all &&
        git bundle create b2.bundle main &&
        mkdir dir &&
@@ -29,7 +33,9 @@ test_expect_success 'preparing origin repository' '
 test_expect_success 'local clone without .git suffix' '
        git clone -l -s a b &&
        (cd b &&
-       test "$(git config --bool core.bare)" = false &&
+       echo false >expect &&
+       git config --bool core.bare >actual &&
+       test_cmp expect actual &&
        git fetch)
 '
 
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 6c8d4c6cf1c8e0f98e2a6cccfec798c19b1954a0..a73b4d4ff6a0d26e925ae7f6a0e8e34a1e138836 100755 (executable)
@@ -244,15 +244,28 @@ test_expect_success 'push with ssh:// using protocol v1' '
        grep "push< version 1" log
 '
 
+test_expect_success 'clone propagates object-format from empty repo' '
+       test_when_finished "rm -fr src256 dst256" &&
+
+       echo sha256 >expect &&
+       git init --object-format=sha256 src256 &&
+       git clone --no-local src256 dst256 &&
+       git -C dst256 rev-parse --show-object-format >actual &&
+
+       test_cmp expect actual
+'
+
 # Test protocol v1 with 'http://' transport
 #
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
-test_expect_success 'create repo to be served by http:// transport' '
+test_expect_success 'create repos to be served by http:// transport' '
        git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
        git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" config http.receivepack true &&
-       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one &&
+       git init --object-format=sha256 "$HTTPD_DOCUMENT_ROOT_PATH/sha256" &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/sha256" config http.receivepack true
 '
 
 test_expect_success 'clone with http:// using protocol v1' '
@@ -269,6 +282,20 @@ test_expect_success 'clone with http:// using protocol v1' '
        grep "git< version 1" log
 '
 
+test_expect_success 'clone with http:// using protocol v1 with empty SHA-256 repo' '
+       GIT_TRACE_PACKET=1 GIT_TRACE_CURL=1 git -c protocol.version=1 \
+               clone "$HTTPD_URL/smart/sha256" sha256 2>log &&
+
+       echo sha256 >expect &&
+       git -C sha256 rev-parse --show-object-format >actual &&
+       test_cmp expect actual &&
+
+       # Client requested to use protocol v1
+       grep "Git-Protocol: version=1" log &&
+       # Server responded using protocol v1
+       grep "git< version 1" log
+'
+
 test_expect_success 'fetch with http:// using protocol v1' '
        test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two &&
 
index e4db7513f42192895e33e7eec431c73bec0007d8..6af5c2062fd16cc8c5549ee888d952966d41c4a3 100755 (executable)
@@ -269,6 +269,17 @@ test_expect_success 'clone propagates unborn HEAD from non-empty repo' '
        grep "warning: remote HEAD refers to nonexistent ref" stderr
 '
 
+test_expect_success 'clone propagates object-format from empty repo' '
+       test_when_finished "rm -fr src256 dst256" &&
+
+       echo sha256 >expect &&
+       git init --object-format=sha256 src256 &&
+       git clone src256 dst256 &&
+       git -C dst256 rev-parse --show-object-format >actual &&
+
+       test_cmp expect actual
+'
+
 test_expect_success 'bare clone propagates unborn HEAD from non-empty repo' '
        test_when_finished "rm -rf file_unborn_parent file_unborn_child.git" &&
 
@@ -728,6 +739,33 @@ test_expect_success 'file:// --negotiate-only with protocol v0' '
        test_i18ngrep "negotiate-only requires protocol v2" err
 '
 
+test_expect_success 'push with custom path does not request v2' '
+       rm -f env.trace &&
+       git -C client push \
+               --receive-pack="env >../env.trace; git-receive-pack" \
+               origin HEAD:refs/heads/custom-push-test &&
+       test_path_is_file env.trace &&
+       ! grep ^GIT_PROTOCOL env.trace
+'
+
+test_expect_success 'fetch with custom path does request v2' '
+       rm -f env.trace &&
+       git -C client fetch \
+               --upload-pack="env >../env.trace; git-upload-pack" \
+               origin HEAD &&
+       grep ^GIT_PROTOCOL=version=2 env.trace
+'
+
+test_expect_success 'archive with custom path does not request v2' '
+       rm -f env.trace &&
+       git -C client archive \
+               --exec="env >../env.trace; git-upload-archive" \
+               --remote=origin \
+               HEAD >/dev/null &&
+       test_path_is_file env.trace &&
+       ! grep ^GIT_PROTOCOL env.trace
+'
+
 # Test protocol v2 with 'http://' transport
 #
 . "$TEST_DIRECTORY"/lib-httpd.sh
index 41d0ca00b1c025beaadedf195586fb81db835bbb..573eb97a0f7f06e45d3358e65be8b55816ea47b3 100755 (executable)
@@ -493,7 +493,7 @@ test_expect_success 'empty email' '
        test_tick &&
        C=$(GIT_AUTHOR_EMAIL= git commit-tree HEAD^{tree} </dev/null) &&
        A=$(git show --pretty=format:%an,%ae,%ad%n -s $C) &&
-       verbose test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700"
+       test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700"
 '
 
 test_expect_success 'del LF before empty (1)' '
index 05162512a09d422a9592a112a1d613d34be4f5ed..a57f1ae2baa4a72e88183fcaa3b55802a80599ef 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,12 @@ 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
 
 test_expect_success 'not only --stdin' '
        cat >expect <<-EOF &&
@@ -78,4 +86,45 @@ 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_done
index aabf590dda61d1ea1b7c70e79bbfa00819ea235e..67d523d40571b89b50cc5ca655ec77198c1a3ae3 100755 (executable)
@@ -187,7 +187,7 @@ test_expect_success 'rev-parse --exclude=ref with --remotes=glob' '
        compare rev-parse "--exclude=upstream/x --remotes=upstream/*" "upstream/one upstream/two"
 '
 
-for section in receive uploadpack
+for section in fetch receive uploadpack
 do
        test_expect_success "rev-parse --exclude-hidden=$section with --all" '
                compare "-c transfer.hideRefs=refs/remotes/ rev-parse" "--branches --tags" "--exclude-hidden=$section --all"
index 7d40994991e423a21ae384010c00b5eb71c64502..3e6bcbf30cdaf0e623ae73858a4f98838e03255c 100755 (executable)
@@ -10,6 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bundle.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 
 for cmd in create verify list-heads unbundle
 do
@@ -606,4 +607,48 @@ test_expect_success 'verify catches unreachable, broken prerequisites' '
        )
 '
 
+test_expect_success 'bundle progress includes write phase' '
+       GIT_PROGRESS_DELAY=0 \
+               git bundle create --progress out.bundle --all 2>err &&
+       grep 'Writing' err
+'
+
+test_expect_success TTY 'create --quiet disables all bundle progress' '
+       test_terminal env GIT_PROGRESS_DELAY=0 \
+               git bundle create --quiet out.bundle --all 2>err &&
+       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 &&
+
+       git bundle verify - <some.bundle 2>err &&
+       grep "<stdin> is okay" err &&
+
+       git bundle list-heads some.bundle >expect &&
+       git bundle list-heads - <some.bundle >actual &&
+       test_cmp expect actual &&
+
+       git bundle unbundle some.bundle >expect &&
+       git bundle unbundle - <some.bundle >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'send a bundle to standard output' '
+       git bundle create - --all HEAD >bundle-one &&
+       mkdir -p down &&
+       git -C down bundle create - --all HEAD >bundle-two &&
+       git bundle verify bundle-one &&
+       git bundle verify bundle-two &&
+       git ls-remote bundle-one >expect &&
+       git ls-remote bundle-two >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 11c50b7c0dd85c629ef9687eb81d36543939bddd..1a9d37e63862f03877fe3d02b94ec8428e7ea01a 100755 (executable)
@@ -22,7 +22,7 @@ test_expect_success 'invalid section' '
        test_cmp expected err
 '
 
-for section in receive uploadpack
+for section in fetch receive uploadpack
 do
        test_expect_success "$section: passed multiple times" '
                echo "fatal: --exclude-hidden= passed more than once" >expected &&
index 3ba4fdf6153b69bce18bef335970742701b2dd34..fb01bd6abce2c815b6f50f75e27e2c8f567cf09c 100755 (executable)
@@ -122,6 +122,29 @@ test_expect_success 'bisect start without -- takes unknown arg as pathspec' '
        grep bar ".git/BISECT_NAMES"
 '
 
+test_expect_success 'bisect reset: back in a branch checked out also elsewhere' '
+       echo "shared" > branch.expect &&
+       test_bisect_reset() {
+               git -C $1 bisect start &&
+               git -C $1 bisect good $HASH1 &&
+               git -C $1 bisect bad $HASH3 &&
+               git -C $1 bisect reset &&
+               git -C $1 branch --show-current > branch.output &&
+               cmp branch.expect branch.output
+       } &&
+       test_when_finished "
+               git worktree remove wt1 &&
+               git worktree remove wt2 &&
+               git branch -d shared
+       " &&
+       git worktree add wt1 -b shared &&
+       git worktree add wt2 -f shared &&
+       # we test in both worktrees to ensure that works
+       # as expected with "first" and "next" worktrees
+       test_bisect_reset wt1 &&
+       test_bisect_reset wt2
+'
+
 test_expect_success 'bisect reset: back in the main branch' '
        git bisect reset &&
        echo "* main" > branch.expect &&
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 c466fd989f168b0fc696e83516474f11040a58be..1b84bf66e0d41ec584e0960a95e9f38ec70452b4 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
 
@@ -447,6 +448,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 +597,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 +1017,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 +1138,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
@@ -1374,6 +1559,14 @@ test_expect_success 'for-each-ref --ignore-case ignores case' '
        test_cmp expect actual
 '
 
+test_expect_success 'for-each-ref --omit-empty works' '
+       git for-each-ref --format="%(refname)" >actual &&
+       test_line_count -gt 1 actual &&
+       git for-each-ref --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual &&
+       echo refs/heads/main >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '
        # name refs numerically to avoid case-insensitive filesystem conflicts
        nr=0 &&
@@ -1464,4 +1657,245 @@ sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)"
 sig_crlf=${sig_crlf%dummy}
 test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
 
+test_expect_success 'git for-each-ref --stdin: empty' '
+       >in &&
+       git for-each-ref --format="%(refname)" --stdin <in >actual &&
+       git for-each-ref --format="%(refname)" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git for-each-ref --stdin: fails if extra args' '
+       >in &&
+       test_must_fail git for-each-ref --format="%(refname)" \
+               --stdin refs/heads/extra <in 2>err &&
+       grep "unknown arguments supplied with --stdin" err
+'
+
+test_expect_success 'git for-each-ref --stdin: matches' '
+       cat >in <<-EOF &&
+       refs/tags/multi*
+       refs/heads/amb*
+       EOF
+
+       cat >expect <<-EOF &&
+       refs/heads/ambiguous
+       refs/tags/multi-ref1-100000-user1
+       refs/tags/multi-ref1-100000-user2
+       refs/tags/multi-ref1-200000-user1
+       refs/tags/multi-ref1-200000-user2
+       refs/tags/multi-ref2-100000-user1
+       refs/tags/multi-ref2-100000-user2
+       refs/tags/multi-ref2-200000-user1
+       refs/tags/multi-ref2-200000-user2
+       refs/tags/multiline
+       EOF
+
+       git for-each-ref --format="%(refname)" --stdin <in >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git for-each-ref with non-existing refs' '
+       cat >in <<-EOF &&
+       refs/heads/this-ref-does-not-exist
+       refs/tags/bogus
+       EOF
+
+       git for-each-ref --format="%(refname)" --stdin <in >actual &&
+       test_must_be_empty actual &&
+
+       xargs git for-each-ref --format="%(refname)" <in >actual &&
+       test_must_be_empty actual
+'
+
+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>out.raw &&
+       grep -Ev "checking the trustdb|PGP trust model" out.raw >out &&
+       head -3 out >expect &&
+       tail -1 out >>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 bfda1f46ad25f49c7d51ce2e5853b1818314010f..2667dd13fe33893086e2bdf14a94a6f3c8648d84 100755 (executable)
@@ -54,4 +54,18 @@ test_expect_success 'Missing objects are reported correctly' '
        test_must_be_empty brief-err
 '
 
+test_expect_success 'ahead-behind requires an argument' '
+       test_must_fail git for-each-ref \
+               --format="%(ahead-behind)" 2>err &&
+       echo "fatal: expected format: %(ahead-behind:<committish>)" >expect &&
+       test_cmp expect err
+'
+
+test_expect_success 'missing ahead-behind base' '
+       test_must_fail git for-each-ref \
+               --format="%(ahead-behind:refs/heads/missing)" 2>err &&
+       echo "fatal: failed to find '\''refs/heads/missing'\''" >expect &&
+       test_cmp expect err
+'
+
 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..9677180a5b3392da63ab32f4462c5ec89a9958f3 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,23 @@ 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 &&
+       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 d9acb639512ae6bdf30c8bdd4a0b4d498541dd84..69509d0c11db655a12fc6ed20215ed25976c46eb 100755 (executable)
@@ -210,90 +210,95 @@ prepare_cruft_history () {
        git reset HEAD^^
 }
 
-assert_cruft_packs () {
-       find .git/objects/pack -name "*.mtimes" >mtimes &&
-       sed -e 's/\.mtimes$/\.pack/g' mtimes >packs &&
-
-       test_file_not_empty packs &&
-       while read pack
-       do
-               test_path_is_file "$pack" || return 1
-       done <packs
-}
-
 assert_no_cruft_packs () {
        find .git/objects/pack -name "*.mtimes" >mtimes &&
        test_must_be_empty mtimes
 }
 
-test_expect_success 'gc --cruft generates a cruft pack' '
-       test_when_finished "rm -fr crufts" &&
-       git init crufts &&
+for argv in \
+       "gc" \
+       "-c gc.cruftPacks=true gc" \
+       "-c gc.cruftPacks=false gc --cruft"
+do
+       test_expect_success "git $argv generates a cruft pack" '
+               test_when_finished "rm -fr repo" &&
+               git init repo &&
+               (
+                       cd repo &&
+
+                       prepare_cruft_history &&
+                       git $argv &&
+
+                       find .git/objects/pack -name "*.mtimes" >mtimes &&
+                       sed -e 's/\.mtimes$/\.pack/g' mtimes >packs &&
+
+                       test_file_not_empty packs &&
+                       while read pack
+                       do
+                               test_path_is_file "$pack" || return 1
+                       done <packs
+               )
+       '
+done
+
+for argv in \
+       "gc --no-cruft" \
+       "-c gc.cruftPacks=false gc" \
+       "-c gc.cruftPacks=true gc --no-cruft"
+do
+       test_expect_success "git $argv does not generate a cruft pack" '
+               test_when_finished "rm -fr repo" &&
+               git init repo &&
+               (
+                       cd repo &&
+
+                       prepare_cruft_history &&
+                       git $argv &&
+
+                       assert_no_cruft_packs
+               )
+       '
+done
+
+test_expect_success '--keep-largest-pack ignores cruft packs' '
+       test_when_finished "rm -fr repo" &&
+       git init repo &&
        (
-               cd crufts &&
+               cd repo &&
 
+               # Generate a pack for reachable objects (of which there
+               # are 3), and one for unreachable objects (of which
+               # there are 6).
                prepare_cruft_history &&
                git gc --cruft &&
-               assert_cruft_packs
-       )
-'
-
-test_expect_success 'gc.cruftPacks=true generates a cruft pack' '
-       test_when_finished "rm -fr crufts" &&
-       git init crufts &&
-       (
-               cd crufts &&
-
-               prepare_cruft_history &&
-               git -c gc.cruftPacks=true gc &&
-               assert_cruft_packs
-       )
-'
-
-test_expect_success 'feature.experimental=true generates a cruft pack' '
-       git init crufts &&
-       test_when_finished "rm -fr crufts" &&
-       (
-               cd crufts &&
 
-               prepare_cruft_history &&
-               git -c feature.experimental=true gc &&
-               assert_cruft_packs
-       )
-'
+               mtimes="$(find .git/objects/pack -type f -name "pack-*.mtimes")" &&
+               sz="$(test_file_size "${mtimes%.mtimes}.pack")" &&
 
-test_expect_success 'feature.experimental=false allows explicit cruft packs' '
-       git init crufts &&
-       test_when_finished "rm -fr crufts" &&
-       (
-               cd crufts &&
+               # Ensure that the cruft pack gets removed (due to
+               # `--prune=now`) despite it being the largest pack.
+               git -c gc.bigPackThreshold=$sz gc --cruft --prune=now &&
 
-               prepare_cruft_history &&
-               git -c gc.cruftPacks=true -c feature.experimental=false gc &&
-               assert_cruft_packs
+               assert_no_cruft_packs
        )
 '
 
-test_expect_success 'feature.experimental=true can be overridden' '
-       git init crufts &&
-       test_when_finished "rm -fr crufts" &&
+test_expect_success 'gc.bigPackThreshold ignores cruft packs' '
+       test_when_finished "rm -fr repo" &&
+       git init repo &&
        (
-               cd crufts &&
+               cd repo &&
 
+               # Generate a pack for reachable objects (of which there
+               # are 3), and one for unreachable objects (of which
+               # there are 6).
                prepare_cruft_history &&
-               git -c feature.expiremental=true -c gc.cruftPacks=false gc &&
-               assert_no_cruft_packs
-       )
-'
+               git gc --cruft &&
 
-test_expect_success 'feature.experimental=false avoids cruft packs by default' '
-       git init crufts &&
-       test_when_finished "rm -fr crufts" &&
-       (
-               cd crufts &&
+               # Ensure that the cruft pack gets removed (due to
+               # `--prune=now`) despite it being the largest pack.
+               git gc --cruft --prune=now --keep-largest-pack &&
 
-               prepare_cruft_history &&
-               git -c feature.experimental=false gc &&
                assert_no_cruft_packs
        )
 '
index 3968b47ed53b7e55eab26fdf8e34aa1472a1bf78..4521508b83a6560e6d025dca1750838f083fdc89 100755 (executable)
@@ -101,7 +101,7 @@ do
        '
 
        test_expect_success "simultaneous gc ($title)" '
-               git gc --prune=12.hours.ago
+               git gc --no-cruft --prune=12.hours.ago
        '
 
        test_expect_success "finish writing out commit ($title)" '
@@ -131,7 +131,7 @@ do
        '
 
        test_expect_success "simultaneous gc ($title)" '
-               git gc --prune=12.hours.ago
+               git gc --no-cruft --prune=12.hours.ago
        '
 
        # tree should have been refreshed by write-tree
@@ -151,8 +151,8 @@ test_expect_success 'do not complain about existing broken links (commit)' '
        some message
        EOF
        commit=$(git hash-object -t commit -w broken-commit) &&
-       git gc -q 2>stderr &&
-       verbose git cat-file -e $commit &&
+       git gc --no-cruft -q 2>stderr &&
+       git cat-file -e $commit &&
        test_must_be_empty stderr
 '
 
@@ -161,7 +161,7 @@ test_expect_success 'do not complain about existing broken links (tree)' '
        100644 blob $(test_oid 003)     foo
        EOF
        tree=$(git mktree --missing <broken-tree) &&
-       git gc -q 2>stderr &&
+       git gc --no-cruft -q 2>stderr &&
        git cat-file -e $tree &&
        test_must_be_empty stderr
 '
@@ -176,7 +176,7 @@ test_expect_success 'do not complain about existing broken links (tag)' '
        this is a broken tag
        EOF
        tag=$(git hash-object -t tag -w broken-tag) &&
-       git gc -q 2>stderr &&
+       git gc --no-cruft -q 2>stderr &&
        git cat-file -e $tag &&
        test_must_be_empty stderr
 '
index 338a9c46a24b02caf471da4afb1cff14a75b6f2f..b330945f497840bc723c7dba4ea237babf09b0d4 100755 (executable)
@@ -443,4 +443,173 @@ test_expect_success 'get_reachable_subset:none' '
        test_all_modes get_reachable_subset
 '
 
+test_expect_success 'for-each-ref ahead-behind:linear' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-1-3
+       refs/heads/commit-1-5
+       refs/heads/commit-1-8
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1 0 8
+       refs/heads/commit-1-3 0 6
+       refs/heads/commit-1-5 0 4
+       refs/heads/commit-1-8 0 1
+       EOF
+       run_all_modes git for-each-ref \
+               --format="%(refname) %(ahead-behind:commit-1-9)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:all' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-2-4
+       refs/heads/commit-4-2
+       refs/heads/commit-4-4
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1 0 24
+       refs/heads/commit-2-4 0 17
+       refs/heads/commit-4-2 0 17
+       refs/heads/commit-4-4 0 9
+       EOF
+       run_all_modes git for-each-ref \
+               --format="%(refname) %(ahead-behind:commit-5-5)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:some' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-5-3
+       refs/heads/commit-4-8
+       refs/heads/commit-9-9
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1 0 53
+       refs/heads/commit-4-8 8 30
+       refs/heads/commit-5-3 0 39
+       refs/heads/commit-9-9 27 0
+       EOF
+       run_all_modes git for-each-ref \
+               --format="%(refname) %(ahead-behind:commit-9-6)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:some, multibase' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-5-3
+       refs/heads/commit-7-8
+       refs/heads/commit-4-8
+       refs/heads/commit-9-9
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1 0 53 0 53
+       refs/heads/commit-4-8 8 30 0 22
+       refs/heads/commit-5-3 0 39 0 39
+       refs/heads/commit-7-8 14 12 8 6
+       refs/heads/commit-9-9 27 0 27 0
+       EOF
+       run_all_modes git for-each-ref \
+               --format="%(refname) %(ahead-behind:commit-9-6) %(ahead-behind:commit-6-9)" \
+               --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:none' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-7-5
+       refs/heads/commit-4-8
+       refs/heads/commit-9-9
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-4-8 16 16
+       refs/heads/commit-7-5 7 4
+       refs/heads/commit-9-9 49 0
+       EOF
+       run_all_modes git for-each-ref \
+               --format="%(refname) %(ahead-behind:commit-8-4)" --stdin
+'
+
+test_expect_success 'for-each-ref merged:linear' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-1-3
+       refs/heads/commit-1-5
+       refs/heads/commit-1-8
+       refs/heads/commit-2-1
+       refs/heads/commit-5-1
+       refs/heads/commit-9-1
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-1-3
+       refs/heads/commit-1-5
+       refs/heads/commit-1-8
+       EOF
+       run_all_modes git for-each-ref --merged=commit-1-9 \
+               --format="%(refname)" --stdin
+'
+
+test_expect_success 'for-each-ref merged:all' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-2-4
+       refs/heads/commit-4-2
+       refs/heads/commit-4-4
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-2-4
+       refs/heads/commit-4-2
+       refs/heads/commit-4-4
+       EOF
+       run_all_modes git for-each-ref --merged=commit-5-5 \
+               --format="%(refname)" --stdin
+'
+
+test_expect_success 'for-each-ref ahead-behind:some' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-5-3
+       refs/heads/commit-4-8
+       refs/heads/commit-9-9
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-5-3
+       EOF
+       run_all_modes git for-each-ref --merged=commit-9-6 \
+               --format="%(refname)" --stdin
+'
+
+test_expect_success 'for-each-ref merged:some, multibase' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-5-3
+       refs/heads/commit-7-8
+       refs/heads/commit-4-8
+       refs/heads/commit-9-9
+       EOF
+       cat >expect <<-\EOF &&
+       refs/heads/commit-1-1
+       refs/heads/commit-4-8
+       refs/heads/commit-5-3
+       EOF
+       run_all_modes git for-each-ref \
+               --merged=commit-5-8 \
+               --merged=commit-8-5 \
+               --format="%(refname)" \
+               --stdin
+'
+
+test_expect_success 'for-each-ref merged:none' '
+       cat >input <<-\EOF &&
+       refs/heads/commit-7-5
+       refs/heads/commit-4-8
+       refs/heads/commit-9-9
+       EOF
+       >expect &&
+       run_all_modes git for-each-ref --merged=commit-8-4 \
+               --format="%(refname)" --stdin
+'
+
 test_done
index d72cef88264ec3dff713b12253df7a6dd5a4724e..f136ea76f7f8a04c7b2b9c5dbf38ca1a50260819 100755 (executable)
@@ -4,6 +4,10 @@ test_description='git mv in subdirs'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff-data.sh
 
+index_at_path () {
+       git ls-files --format='%(objectmode) %(objectname) %(stage)' "$@"
+}
+
 test_expect_success 'mv -f refreshes updated index entry' '
        echo test >bar &&
        git add bar &&
@@ -170,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/ .
 '
@@ -187,7 +198,8 @@ test_expect_success "Michael Cassar's test case" '
        git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
 
        T=$(git write-tree) &&
-       git ls-tree -r $T | verbose grep partA/outline.txt
+       git ls-tree -r $T >out &&
+       grep partA/outline.txt out
 '
 
 rm -fr papers partA path?
@@ -260,12 +272,12 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' '
        git init &&
        echo 1 >dirty &&
        git add dirty &&
-       entry="$(git ls-files --stage dirty | cut -f 1)" &&
+       entry="$(index_at_path dirty)" &&
        git mv dirty dirty2 &&
-       test "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" &&
+       test "$entry" = "$(index_at_path dirty2)" &&
        echo 2 >dirty2 &&
        git mv dirty2 dirty &&
-       test "$entry" = "$(git ls-files --stage dirty | cut -f 1)"
+       test "$entry" = "$(index_at_path dirty)"
 '
 
 rm -f dirty dirty2
@@ -342,7 +354,7 @@ test_expect_success 'git mv cannot move a submodule in a file' '
 '
 
 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
-       entry="$(git ls-files --stage sub | cut -f 1)" &&
+       entry="$(index_at_path sub)" &&
        git rm .gitmodules &&
        (
                cd sub &&
@@ -353,7 +365,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm
        mkdir mod &&
        git mv sub mod/sub &&
        test_path_is_missing sub &&
-       test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+       test "$entry" = "$(index_at_path mod/sub)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
        git diff-files --quiet
@@ -363,7 +375,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
        rm -rf mod &&
        git reset --hard &&
        git submodule update &&
-       entry="$(git ls-files --stage sub | cut -f 1)" &&
+       entry="$(index_at_path sub)" &&
        (
                cd sub &&
                rm -f .git &&
@@ -373,7 +385,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
        mkdir mod &&
        git mv sub mod/sub &&
        test_path_is_missing sub &&
-       test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+       test "$entry" = "$(index_at_path mod/sub)" &&
        git -C mod/sub status &&
        echo mod/sub >expected &&
        git config -f .gitmodules submodule.sub.path >actual &&
@@ -386,11 +398,11 @@ test_expect_success 'git mv moves a submodule with gitfile' '
        rm -rf mod &&
        git reset --hard &&
        git submodule update &&
-       entry="$(git ls-files --stage sub | cut -f 1)" &&
+       entry="$(index_at_path sub)" &&
        mkdir mod &&
        git -C mod mv ../sub/ . &&
        test_path_is_missing sub &&
-       test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+       test "$entry" = "$(index_at_path mod/sub)" &&
        git -C mod/sub status &&
        echo mod/sub >expected &&
        git config -f .gitmodules submodule.sub.path >actual &&
@@ -404,12 +416,12 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' '
        git reset --hard &&
        git submodule update &&
        git rm .gitmodules &&
-       entry="$(git ls-files --stage sub | cut -f 1)" &&
+       entry="$(index_at_path sub)" &&
        mkdir mod &&
        git mv sub mod/sub 2>actual.err &&
        test_must_be_empty actual.err &&
        test_path_is_missing sub &&
-       test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+       test "$entry" = "$(index_at_path mod/sub)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
        git diff-files --quiet
@@ -420,7 +432,7 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
        git reset --hard &&
        git submodule update &&
        git config -f .gitmodules foo.bar true &&
-       entry="$(git ls-files --stage sub | cut -f 1)" &&
+       entry="$(index_at_path sub)" &&
        mkdir mod &&
        test_must_fail git mv sub mod/sub 2>actual.err &&
        test_file_not_empty actual.err &&
@@ -430,7 +442,7 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
        git mv sub mod/sub 2>actual.err &&
        test_must_be_empty actual.err &&
        test_path_is_missing sub &&
-       test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+       test "$entry" = "$(index_at_path mod/sub)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
        git diff-files --quiet
@@ -442,13 +454,13 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule
        git submodule update &&
        git config -f .gitmodules --remove-section submodule.sub &&
        git add .gitmodules &&
-       entry="$(git ls-files --stage sub | cut -f 1)" &&
+       entry="$(index_at_path sub)" &&
        echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
        mkdir mod &&
        git mv sub mod/sub 2>actual.err &&
        test_cmp expect.err actual.err &&
        test_path_is_missing sub &&
-       test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+       test "$entry" = "$(index_at_path mod/sub)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
        git diff-files --quiet
index 9aa1660651b8a96397ce2a83cb3d107c8b7d43dc..e689db429292e60162d4f8f89905cc8489d7a3e0 100755 (executable)
@@ -792,6 +792,34 @@ test_expect_success 'annotations for blobs are empty' '
        test_cmp expect actual
 '
 
+# Run this before doing any signing, so the test has the same results
+# regardless of the GPG prereq.
+test_expect_success 'git tag --format with ahead-behind' '
+       test_when_finished git reset --hard tag-one-line &&
+       git commit --allow-empty -m "left" &&
+       git tag -a -m left tag-left &&
+       git reset --hard HEAD~1 &&
+       git commit --allow-empty -m "right" &&
+       git tag -a -m left tag-right &&
+
+       # Use " !" at the end to demonstrate whitespace
+       # around empty ahead-behind token for tag-blob.
+       cat >expect <<-EOF &&
+       refs/tags/tag-blob  !
+       refs/tags/tag-left 1 1 !
+       refs/tags/tag-lines 0 1 !
+       refs/tags/tag-one-line 0 1 !
+       refs/tags/tag-right 0 0 !
+       refs/tags/tag-zero-lines 0 1 !
+       EOF
+       git tag -l --format="%(refname) %(ahead-behind:HEAD) !" >actual 2>err &&
+       grep "refs/tags/tag" actual >actual.focus &&
+       test_cmp expect actual.focus &&
+
+       # Error reported for tags that point to non-commits.
+       grep "error: object [0-9a-f]* is a blob, not a commit" err
+'
+
 # trying to verify annotated non-signed tags:
 
 test_expect_success GPG \
@@ -1843,6 +1871,23 @@ test_expect_success 'invalid sort parameter in configuratoin' '
        test_must_fail git tag -l "foo*"
 '
 
+test_expect_success 'version sort handles empty value for versionsort.{prereleaseSuffix,suffix}' '
+       cp .git/config .git/config.orig &&
+       test_when_finished mv .git/config.orig .git/config &&
+
+       cat >>.git/config <<-\EOF &&
+       [versionsort]
+               prereleaseSuffix
+               suffix
+       EOF
+       cat >expect <<-\EOF &&
+       error: missing value for '\''versionsort.suffix'\''
+       error: missing value for '\''versionsort.prereleasesuffix'\''
+       EOF
+       git tag -l --sort=version:refname 2>actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'version sort with prerelease reordering' '
        test_config versionsort.prereleaseSuffix -rc &&
        git tag foo1.6-rc1 &&
@@ -2001,6 +2046,22 @@ test_expect_success '--format should list tags as per format given' '
        test_cmp expect actual
 '
 
+test_expect_success '--format --omit-empty works' '
+       cat >expect <<-\EOF &&
+       refname : refs/tags/v1.0
+
+       refname : refs/tags/v1.1.3
+       EOF
+       git tag -l --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual &&
+       test_cmp expect actual &&
+       cat >expect <<-\EOF &&
+       refname : refs/tags/v1.0
+       refname : refs/tags/v1.1.3
+       EOF
+       git tag -l --omit-empty --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git tag -l with --format="%(rest)" must fail' '
        test_must_fail git tag -l --format="%(rest)" "v1*"
 '
@@ -2127,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 36eb86a4b19f3c758b2830fe5157a1667069321a..20913b371344264a6dc9c84b58c3b6de3b46e226 100755 (executable)
@@ -200,4 +200,14 @@ test_expect_success GPGSSH 'verifying a forged tag with --format should fail sil
        test_must_be_empty actual-forged
 '
 
+test_expect_success GPGSSH 'rev-list --format=%G' '
+       test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+       git rev-list -1 --format="%G? %H" sixth-signed >actual &&
+       cat >expect <<-EOF &&
+       commit $(git rev-parse sixth-signed^0)
+       G $(git rev-parse sixth-signed^0)
+       EOF
+       test_cmp expect actual
+'
+
 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..35b9e6ed6b5ba337d9fb4603281500656313ed1d 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 () {
index c975eb54d234d77b2f13df2a96acd4cbefb93865..0ef7b78457368fd8f0e403907e7d582e97e62248 100755 (executable)
@@ -120,7 +120,7 @@ test_expect_success 'git clean with relative prefix' '
                grep part3 |
                sed -n -e "s|^Would remove ||p"
        ) &&
-       verbose test "$would_clean" = ../src/part3.c
+       test "$would_clean" = ../src/part3.c
 '
 
 test_expect_success 'git clean with absolute path' '
@@ -133,7 +133,7 @@ test_expect_success 'git clean with absolute path' '
                grep part3 |
                sed -n -e "s|^Would remove ||p"
        ) &&
-       verbose test "$would_clean" = ../src/part3.c
+       test "$would_clean" = ../src/part3.c
 '
 
 test_expect_success 'git clean with out of work tree relative path' '
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 b19792b326901bbb8c00c20f07dbb38b322a9e74..2b3c363078bc06219c8b5c16b02f331b447f5102 100755 (executable)
@@ -56,12 +56,15 @@ chmod a+x fake-editor.sh
 
 test_expect_success 'interactive rebase with a dirty submodule' '
 
-       test submodule = $(git diff --name-only) &&
+       echo submodule >expect &&
+       git diff --name-only >actual &&
+       test_cmp expect actual &&
        HEAD=$(git rev-parse HEAD) &&
        GIT_EDITOR="\"$(pwd)/fake-editor.sh\"" EDITOR_TEXT="pick $HEAD" \
                git rebase -i HEAD^ &&
-       test submodule = $(git diff --name-only)
-
+       echo submodule >expect &&
+       git diff --name-only >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'rebase with dirty file and submodule fails' '
@@ -83,11 +86,19 @@ test_expect_success 'stash with a dirty submodule' '
        CURRENT=$(cd submodule && git rev-parse HEAD) &&
        git stash &&
        test new != $(cat file) &&
-       test submodule = $(git diff --name-only) &&
-       test $CURRENT = $(cd submodule && git rev-parse HEAD) &&
+       echo submodule >expect &&
+       git diff --name-only >actual &&
+       test_cmp expect actual &&
+
+       echo "$CURRENT" >expect &&
+       git -C submodule rev-parse HEAD >actual &&
+       test_cmp expect actual &&
+
        git stash apply &&
        test new = $(cat file) &&
-       test $CURRENT = $(cd submodule && git rev-parse HEAD)
+       echo "$CURRENT" >expect &&
+       git -C submodule rev-parse HEAD >actual &&
+       test_cmp expect actual
 
 '
 
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 7cdc26376490e80274c4f699ddd0b00c25e4d9cd..887d181b72ec05ab68f619de3948d667179dcb68 100755 (executable)
@@ -51,6 +51,22 @@ test_expect_success 'is-active works with submodule.<name>.active config' '
        test-tool -C super submodule is-active sub1
 '
 
+test_expect_success 'is-active handles submodule.active config missing a value' '
+       cp super/.git/config super/.git/config.orig &&
+       test_when_finished mv super/.git/config.orig super/.git/config &&
+
+       cat >>super/.git/config <<-\EOF &&
+       [submodule]
+               active
+       EOF
+
+       cat >expect <<-\EOF &&
+       error: missing value for '\''submodule.active'\''
+       EOF
+       test-tool -C super submodule is-active sub1 2>actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'is-active works with basic submodule.active config' '
        test_when_finished "git -C super config submodule.sub1.URL ../sub" &&
        test_when_finished "git -C super config --unset-all submodule.active" &&
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 07ca46fb0d539c62c7dcbe066b8c95e550d0b3a3..d1255228d5ffaa2b7b7333000e3e39468ee94bb1 100755 (executable)
@@ -102,7 +102,9 @@ test_expect_success 'setup: commit-msg hook that always fails' '
 '
 
 commit_msg_is () {
-       test "$(git log --pretty=format:%s%b -1)" = "$1"
+       printf "%s" "$1" >expect &&
+       git log --pretty=format:%s%b -1 >actual &&
+       test_cmp expect actual
 }
 
 test_expect_success 'with failing hook' '
index aed07c5b622e9a244313e781ceba0e6898024d21..6928fd89f5d887b2f7a3feb9263b39d77affe9aa 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)
index 48f86cb3678140ba1b0f914da8ebb442abd754b8..0d2dd29fe6a12c20ffbbe169afabd4c31bc6545c 100755 (executable)
@@ -218,87 +218,101 @@ 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
+       ultimate
        13B6F51ECDDE430D
        C O Mitter <committer@example.com>
        73D758744BE721698EC54E8713B6F51ECDDE430D
        73D758744BE721698EC54E8713B6F51ECDDE430D
        EOF
-       git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
+       git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
        test_cmp expect actual
 '
 
 test_expect_success GPG 'show bad signature with custom format' '
        cat >expect <<-\EOF &&
        B
+       undefined
        13B6F51ECDDE430D
        C O Mitter <committer@example.com>
 
 
        EOF
-       git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual &&
+       git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual &&
        test_cmp expect actual
 '
 
 test_expect_success GPG 'show untrusted signature with custom format' '
        cat >expect <<-\EOF &&
        U
+       undefined
        65A0EEA02E30CAD7
        Eris Discordia <discord@example.net>
        F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
        D4BE22311AD3131E5EDA29A461092E85B7227189
        EOF
-       git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+       git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
        test_cmp expect actual
 '
 
 test_expect_success GPG 'show untrusted signature with undefined trust level' '
        cat >expect <<-\EOF &&
+       U
        undefined
        65A0EEA02E30CAD7
        Eris Discordia <discord@example.net>
        F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
        D4BE22311AD3131E5EDA29A461092E85B7227189
        EOF
-       git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+       git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
        test_cmp expect actual
 '
 
 test_expect_success GPG 'show untrusted signature with ultimate trust level' '
        cat >expect <<-\EOF &&
+       G
        ultimate
        13B6F51ECDDE430D
        C O Mitter <committer@example.com>
        73D758744BE721698EC54E8713B6F51ECDDE430D
        73D758744BE721698EC54E8713B6F51ECDDE430D
        EOF
-       git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
+       git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
        test_cmp expect actual
 '
 
 test_expect_success GPG 'show unknown signature with custom format' '
        cat >expect <<-\EOF &&
        E
+       undefined
        65A0EEA02E30CAD7
 
 
 
        EOF
-       GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+       GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
        test_cmp expect actual
 '
 
 test_expect_success GPG 'show lack of signature with custom format' '
        cat >expect <<-\EOF &&
        N
+       undefined
 
 
 
 
        EOF
-       git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual &&
+       git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual &&
        test_cmp expect actual
 '
 
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 f2ce14e9071c0a3b071f53186c2d311103883443..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' '
@@ -10,7 +12,8 @@ test_expect_success 'race to create orphan commit' '
        test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&
        git show -s --pretty=format:%s >subject &&
        grep hare subject &&
-       test -z "$(git show -s --pretty=format:%P)"
+       git show -s --pretty=format:%P >out &&
+       test_must_be_empty out
 '
 
 test_expect_success 'race to create non-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 4c0327b2bb27af53e24b4158a63f6d2aec9ae19e..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
 }
@@ -995,4 +1000,41 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' '
        grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
 '
 
+test_expect_success 'split-index and FSMonitor work well together' '
+       git init split-index &&
+       test_when_finished "git -C \"$PWD/split-index\" \
+               fsmonitor--daemon stop" &&
+       (
+               cd split-index &&
+               git config core.splitIndex true &&
+               # force split-index in most cases
+               git config splitIndex.maxPercentChange 99 &&
+               git config core.fsmonitor true &&
+
+               # Create the following commit topology:
+               #
+               # *   merge three
+               # |\
+               # | * three
+               # * | merge two
+               # |\|
+               # | * two
+               # * | one
+               # |/
+               # * 5a5efd7 initial
+
+               test_commit initial &&
+               test_commit two &&
+               test_commit three &&
+               git reset --hard initial &&
+               test_commit one &&
+               test_tick &&
+               git merge two &&
+               test_tick &&
+               git merge three &&
+
+               git rebase --force-rebase -r one
+       )
+'
+
 test_done
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 7b957022f1abbd0b01cf043b52ebfd8a76042929..22b3a85b3e960e4d40024179b1fbaef3355d304d 100755 (executable)
@@ -860,4 +860,42 @@ test_expect_success 'mergetool hideResolved' '
        git commit -m "test resolved with mergetool"
 '
 
+test_expect_success 'mergetool with guiDefault' '
+       test_config merge.guitool myguitool &&
+       test_config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\"" &&
+       test_config mergetool.myguitool.trustExitCode true &&
+       test_when_finished "git reset --hard" &&
+       git checkout -b test$test_count branch1 &&
+       git submodule update -N &&
+       test_must_fail git merge main &&
+
+       test_config mergetool.guiDefault auto &&
+       DISPLAY=SOMETHING && export DISPLAY &&
+       yes "" | git mergetool both &&
+       yes "" | git mergetool file1 file1 &&
+
+       DISPLAY= && export DISPLAY &&
+       yes "" | git mergetool file2 "spaced name" &&
+
+       test_config mergetool.guiDefault true &&
+       yes "" | git mergetool subdir/file3 &&
+
+       yes "d" | git mergetool file11 &&
+       yes "d" | git mergetool file12 &&
+       yes "l" | git mergetool submod &&
+
+       echo "gui main updated" >expect &&
+       test_cmp expect file1 &&
+
+       echo "main new" >expect &&
+       test_cmp expect file2 &&
+
+       echo "gui main new sub" >expect &&
+       test_cmp expect subdir/file3 &&
+
+       echo "branch1 submodule" >expect &&
+       test_cmp expect submod/bar &&
+       git commit -m "branch1 resolved with mergetool"
+'
+
 test_done
index 4aabe98139a37eb8bc1d2f3e824048dbdd7f9915..27b66807cd82cbb93c4985905a8de7945cc17cbc 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
 }
 
@@ -106,6 +110,23 @@ test_expect_success SYMLINKS '--local keeps packs when alternate is objectdir '
        test_cmp expect actual
 '
 
+test_expect_success '--local disables writing bitmaps when connected to alternate ODB' '
+       test_when_finished "rm -rf shared member" &&
+
+       git init shared &&
+       git clone --shared shared member &&
+       (
+               cd member &&
+               test_commit "object" &&
+               GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err &&
+               cat >expect <<-EOF &&
+               warning: disabling bitmap writing, as some objects are not being packed
+               EOF
+               test_cmp expect err &&
+               test_path_is_missing .git/objects/pack-*.bitmap
+       )
+'
+
 test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
        mkdir alt_objects/pack &&
        mv .git/objects/pack/* alt_objects/pack &&
@@ -192,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) &&
@@ -203,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 &&
@@ -443,10 +517,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 &&
@@ -460,7 +534,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' '
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 &&
index 8821fbd2dd55844e54f55553b442ec419755546c..00f28fb558ced5cbb4c7667f9b6ce597ee7fb782 100755 (executable)
@@ -10,6 +10,12 @@ objdir=.git/objects
 packdir=$objdir/pack
 midx=$objdir/pack/multi-pack-index
 
+packed_objects () {
+       git show-index <"$1" >tmp-object-list &&
+       cut -d' ' -f2 tmp-object-list | sort &&
+       rm tmp-object-list
+ }
+
 test_expect_success '--geometric with no packs' '
        git init geometric &&
        test_when_finished "rm -fr geometric" &&
@@ -281,4 +287,162 @@ test_expect_success '--geometric with pack.packSizeLimit' '
        )
 '
 
+test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' '
+       test_when_finished "rm -fr shared member" &&
+
+       # Create a shared repository that will serve as the alternate object
+       # database for the member linked to it. It has got some objects on its
+       # own that are packed into a single packfile.
+       git init shared &&
+       test_commit -C shared common-object &&
+       git -C shared repack -ad &&
+
+       # We create member so that its alternates file points to the shared
+       # repository. We then create a commit in it so that git-repack(1) has
+       # something to repack.
+       # of the shared object database.
+       git clone --shared shared member &&
+       test_commit -C member unique-object &&
+       git -C member repack --geometric=2 --write-midx 2>err &&
+       test_must_be_empty err &&
+
+       # We should see that a new packfile was generated.
+       find shared/.git/objects/pack -type f -name "*.pack" >packs &&
+       test_line_count = 1 packs &&
+
+       # We should also see a multi-pack-index. This multi-pack-index should
+       # never refer to any packfiles in the alternate object database.
+       test_path_is_file member/.git/objects/pack/multi-pack-index &&
+       test-tool read-midx member/.git/objects >packs.midx &&
+       grep "^pack-.*\.idx$" packs.midx | sort >actual &&
+       basename member/.git/objects/pack/pack-*.idx >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '--geometric --with-midx with no local objects' '
+       test_when_finished "rm -fr shared member" &&
+
+       # Create a repository with a single packfile that acts as alternate
+       # object database.
+       git init shared &&
+       test_commit -C shared "shared-objects" &&
+       git -C shared repack -ad &&
+
+       # Create a second repository linked to the first one and perform a
+       # geometric repack on it.
+       git clone --shared shared member &&
+       git -C member repack --geometric 2 --write-midx 2>err &&
+       test_must_be_empty err &&
+
+       # Assert that we wrote neither a new packfile nor a multi-pack-index.
+       # We should not have a packfile because the single packfile in the
+       # alternate object database does not invalidate the geometric sequence.
+       # And we should not have a multi-pack-index because these only index
+       # local packfiles, and there are none.
+       test_dir_is_empty member/$packdir
+'
+
+test_expect_success '--geometric with same pack in main and alternate ODB' '
+       test_when_finished "rm -fr shared member" &&
+
+       # Create a repository with a single packfile that acts as alternate
+       # object database.
+       git init shared &&
+       test_commit -C shared "shared-objects" &&
+       git -C shared repack -ad &&
+
+       # We create the member repository as an exact copy so that it has the
+       # same packfile.
+       cp -r shared member &&
+       test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates &&
+       find shared/.git/objects -type f >expected-files &&
+
+       # Verify that we can repack objects as expected without observing any
+       # error. Having the same packfile in both ODBs used to cause an error
+       # in git-pack-objects(1).
+       git -C member repack --geometric 2 2>err &&
+       test_must_be_empty err &&
+       # Nothing should have changed.
+       find shared/.git/objects -type f >actual-files &&
+       test_cmp expected-files actual-files
+'
+
+test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' '
+       test_when_finished "rm -fr shared member" &&
+
+       git init shared &&
+       test_commit_bulk -C shared --start=1 1 &&
+
+       git clone --shared shared member &&
+       test_commit_bulk -C member --start=2 1 &&
+
+       # Verify that our assumptions actually hold: both generated packfiles
+       # should have three objects and should be non-equal.
+       packed_objects shared/.git/objects/pack/pack-*.idx >shared-objects &&
+       packed_objects member/.git/objects/pack/pack-*.idx >member-objects &&
+       test_line_count = 3 shared-objects &&
+       test_line_count = 3 member-objects &&
+       ! test_cmp shared-objects member-objects &&
+
+       # Perform the geometric repack. With `-l`, we should only see the local
+       # packfile and thus arrive at the conclusion that the geometric
+       # sequence is intact. We thus expect no changes.
+       #
+       # Note that we are tweaking mtimes of the packfiles so that we can
+       # verify they did not change. This is done in order to detect the case
+       # where we do repack objects, but the resulting packfile is the same.
+       test-tool chmtime --verbose =0 member/.git/objects/pack/* >expected-member-packs &&
+       git -C member repack --geometric=2 -l -d &&
+       test-tool chmtime --verbose member/.git/objects/pack/* >actual-member-packs &&
+       test_cmp expected-member-packs actual-member-packs &&
+
+       {
+               packed_objects shared/.git/objects/pack/pack-*.idx &&
+               packed_objects member/.git/objects/pack/pack-*.idx
+       } | sort >expected-objects &&
+
+       # On the other hand, when doing a non-local geometric repack we should
+       # see both packfiles and thus repack them. We expect that the shared
+       # object database was not changed.
+       test-tool chmtime --verbose =0 shared/.git/objects/pack/* >expected-shared-packs &&
+       git -C member repack --geometric=2 -d &&
+       test-tool chmtime --verbose shared/.git/objects/pack/* >actual-shared-packs &&
+       test_cmp expected-shared-packs actual-shared-packs &&
+
+       # Furthermore, we expect that the member repository now has a single
+       # packfile that contains the combined shared and non-shared objects.
+       ls member/.git/objects/pack/pack-*.idx >actual &&
+       test_line_count = 1 actual &&
+       packed_objects member/.git/objects/pack/pack-*.idx >actual-objects &&
+       test_line_count = 6 actual-objects &&
+       test_cmp expected-objects actual-objects
+'
+
+test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' '
+       test_when_finished "rm -fr shared member" &&
+
+       git init shared &&
+       test_commit_bulk -C shared --start=1 1 &&
+
+       git clone --shared shared member &&
+       test_commit_bulk -C member --start=2 1 &&
+
+       # When performing a geometric repack with `-l` while connected to an
+       # alternate object database that has a packfile we do not have full
+       # coverage of objects. As a result, we expect that writing the bitmap
+       # will be disabled.
+       git -C member repack -l --geometric=2 --write-midx --write-bitmap-index 2>err &&
+       cat >expect <<-EOF &&
+       warning: disabling bitmap writing, as some objects are not being packed
+       EOF
+       test_cmp expect err &&
+       test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap &&
+
+       # On the other hand, when we repack without `-l`, we should see that
+       # the bitmap gets created.
+       git -C member repack --geometric=2 --write-midx --write-bitmap-index 2>err &&
+       test_must_be_empty err &&
+       test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap
+'
+
 test_done
index 24297e26ca028bd0b36aa29803a51c6ddde73f0c..59d3847bf87eab5d94fffbc48451665268b2832e 100755 (executable)
@@ -155,6 +155,58 @@ test_expect_success 'difftool honors --gui' '
        test_cmp expect actual
 '
 
+test_expect_success 'difftool with guiDefault auto selects gui tool when there is DISPLAY' '
+       difftool_test_setup &&
+       test_config merge.tool bogus-tool &&
+       test_config diff.tool bogus-tool &&
+       test_config diff.guitool test-tool &&
+       test_config difftool.guiDefault auto &&
+       DISPLAY=SOMETHING && export DISPLAY &&
+
+       echo branch >expect &&
+       git difftool --no-prompt branch >actual &&
+       test_cmp expect actual
+'
+test_expect_success 'difftool with guiDefault auto selects regular tool when no DISPLAY' '
+       difftool_test_setup &&
+       test_config diff.guitool bogus-tool &&
+       test_config diff.tool test-tool &&
+       test_config difftool.guiDefault Auto &&
+       DISPLAY= && export DISPLAY &&
+
+       echo branch >expect &&
+       git difftool --no-prompt branch >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'difftool with guiDefault true selects gui tool' '
+       difftool_test_setup &&
+       test_config diff.tool bogus-tool &&
+       test_config diff.guitool test-tool &&
+       test_config difftool.guiDefault true &&
+
+       DISPLAY= && export DISPLAY &&
+       echo branch >expect &&
+       git difftool --no-prompt branch >actual &&
+       test_cmp expect actual &&
+
+       DISPLAY=Something && export DISPLAY &&
+       echo branch >expect &&
+       git difftool --no-prompt branch >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'difftool --no-gui trumps config guiDefault' '
+       difftool_test_setup &&
+       test_config diff.guitool bogus-tool &&
+       test_config diff.tool test-tool &&
+       test_config difftool.guiDefault true &&
+
+       echo branch >expect &&
+       git difftool --no-prompt --no-gui branch >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'difftool --gui last setting wins' '
        difftool_test_setup &&
        : >expect &&
index 8eded6ab274fafe636151b7903bae3351a27df5c..39d6d713ecbe05e9638f8f6ee3f79ff49628b2cf 100755 (executable)
@@ -1001,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' '
 test_expect_success 'grep with CE_VALID file' '
        git update-index --assume-unchanged t/t &&
        rm t/t &&
-       test "$(git grep test)" = "t/t:test" &&
+       echo "t/t:test" >expect &&
+       git grep test >actual &&
+       test_cmp expect actual &&
        git update-index --no-assume-unchanged t/t &&
        git checkout t/t
 '
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 823331e44a03b2f62e9f1577a84f08863150388d..487e326b3fac126fb611e50851465d7d8b963888 100755 (executable)
@@ -524,6 +524,44 @@ test_expect_success 'register and unregister' '
        git maintenance unregister --config-file ./other --force
 '
 
+test_expect_success 'register with no value for maintenance.repo' '
+       cp .git/config .git/config.orig &&
+       test_when_finished mv .git/config.orig .git/config &&
+
+       cat >>.git/config <<-\EOF &&
+       [maintenance]
+               repo
+       EOF
+       cat >expect <<-\EOF &&
+       error: missing value for '\''maintenance.repo'\''
+       EOF
+       git maintenance register 2>actual &&
+       test_cmp expect actual &&
+       git config maintenance.repo
+'
+
+test_expect_success 'unregister with no value for maintenance.repo' '
+       cp .git/config .git/config.orig &&
+       test_when_finished mv .git/config.orig .git/config &&
+
+       cat >>.git/config <<-\EOF &&
+       [maintenance]
+               repo
+       EOF
+       cat >expect <<-\EOF &&
+       error: missing value for '\''maintenance.repo'\''
+       EOF
+       test_expect_code 128 git maintenance unregister 2>actual.raw &&
+       grep ^error actual.raw >actual &&
+       test_cmp expect actual &&
+       git config maintenance.repo &&
+
+       git maintenance unregister --force 2>actual.raw &&
+       grep ^error actual.raw >actual &&
+       test_cmp expect actual &&
+       git config maintenance.repo
+'
+
 test_expect_success !MINGW 'register and unregister with regex metacharacters' '
        META="a+b*c" &&
        git init "$META" &&
index 323952a572d61b0cff9c05086f9735231c3b0db5..a60b05ad3f09f03433e2b7fe96e095966ddb104a 100755 (executable)
@@ -12,7 +12,7 @@ PREREQ="PERL"
 
 replace_variable_fields () {
        sed     -e "s/^\(Date:\).*/\1 DATE-STRING/" \
-               -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
+               -e "s/^\(Message-ID:\).*/\1 MESSAGE-ID-STRING/" \
                -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/"
 }
 
@@ -47,7 +47,7 @@ clean_fake_sendmail () {
 
 test_expect_success $PREREQ 'Extract patches' '
        patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1) &&
-       threaded_patches=$(git format-patch -o threaded -s --in-reply-to="format" HEAD^1)
+       threaded_patches=$(git format-patch -o threaded --thread=shallow -s --in-reply-to="format" HEAD^1)
 '
 
 # Test no confirm early to ensure remaining tests will not hang
@@ -225,7 +225,7 @@ Cc: cc@example.com,
        two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 In-Reply-To: <unique-message-id@example.com>
 References: <unique-message-id@example.com>
@@ -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' '
@@ -374,13 +375,16 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'
        )
 '
 
-test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '
+test_expect_success $PREREQ 'setup cmd scripts' '
        write_script tocmd-sed <<-\EOF &&
        sed -n -e "s/^tocmd--//p" "$1"
        EOF
-       write_script cccmd-sed <<-\EOF
+       write_script cccmd-sed <<-\EOF &&
        sed -n -e "s/^cccmd--//p" "$1"
        EOF
+       write_script headercmd-sed <<-\EOF
+       sed -n -e "s/^headercmd--//p" "$1"
+       EOF
 '
 
 test_expect_success $PREREQ 'tocmd works' '
@@ -410,6 +414,70 @@ test_expect_success $PREREQ 'cccmd works' '
        grep "^ cccmd@example.com" msgtxt1
 '
 
+test_expect_success $PREREQ 'headercmd works' '
+       clean_fake_sendmail &&
+       cp $patches headercmd.patch &&
+       echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --header-cmd=./headercmd-sed \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               headercmd.patch \
+               &&
+       grep "^X-Debbugs-CC: dummy@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ '--no-header-cmd works' '
+       clean_fake_sendmail &&
+       cp $patches headercmd.patch &&
+       echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --header-cmd=./headercmd-sed \
+               --no-header-cmd \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               headercmd.patch \
+               &&
+       ! grep "^X-Debbugs-CC: dummy@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ 'multiline fields are correctly unfolded' '
+       clean_fake_sendmail &&
+       cp $patches headercmd.patch &&
+       write_script headercmd-multiline <<-\EOF &&
+       echo "X-Debbugs-CC: someone@example.com
+FoldedField: This is a tale
+ best told using
+ multiple lines."
+       EOF
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --header-cmd=./headercmd-multiline \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               headercmd.patch &&
+       grep "^FoldedField: This is a tale best told using multiple lines.$" msgtxt1
+'
+
+# Blank lines in the middle of the output of a command are invalid.
+test_expect_success $PREREQ 'malform output reported on blank lines in command output' '
+       clean_fake_sendmail &&
+       cp $patches headercmd.patch &&
+       write_script headercmd-malformed-output <<-\EOF &&
+       echo "X-Debbugs-CC: someone@example.com
+
+SomeOtherField: someone-else@example.com"
+       EOF
+       ! git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --header-cmd=./headercmd-malformed-output \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               headercmd.patch
+'
+
 test_expect_success $PREREQ 'reject long lines' '
        z8=zzzzzzzz &&
        z64=$z8$z8$z8$z8$z8$z8$z8$z8 &&
@@ -540,7 +608,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
        test_path_is_file my-hooks.ran &&
        cat >expect <<-EOF &&
        fatal: longline.patch: rejected by sendemail-validate hook
-       fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
+       fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
        warning: no patches were sent
        EOF
        test_cmp expect actual
@@ -559,12 +627,49 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
        test_path_is_file my-hooks.ran &&
        cat >expect <<-EOF &&
        fatal: longline.patch: rejected by sendemail-validate hook
-       fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
+       fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
        warning: no patches were sent
        EOF
        test_cmp expect actual
 '
 
+test_expect_success $PREREQ "--validate hook supports header argument" '
+       write_script my-hooks/sendemail-validate <<-\EOF &&
+       if test "$#" -ge 2
+       then
+               grep "X-test-header: v1.0" "$2"
+       else
+               echo "No header arg passed"
+               exit 1
+       fi
+       EOF
+       test_config core.hooksPath "my-hooks" &&
+       rm -fr outdir &&
+       git format-patch \
+               --add-header="X-test-header: v1.0" \
+               -n HEAD^1 -o outdir &&
+       git send-email \
+               --dry-run \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               --validate \
+               outdir/000?-*.patch
+'
+
+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 --validate --to=recipient@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches $threaded_patches &&
+       id0=$(grep "^Message-ID: " $threaded_patches) &&
+       id1=$(grep "^Message-ID: " msgtxt1) &&
+       id2=$(grep "^Message-ID: " msgtxt2) &&
+       test "z$id0" = "z$id2" &&
+       test "z$id1" != "z$id2"
+'
+
 for enc in 7bit 8bit quoted-printable base64
 do
        test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" '
@@ -617,7 +722,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
        sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
        test_cmp expect actual &&
        # Second and subsequent messages are replies to the first one
-       sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
+       sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt1 >expect &&
        sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
        test_cmp expect actual &&
        sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
@@ -637,10 +742,10 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
                2>errors &&
        sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual &&
        test_cmp expect actual &&
-       sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect &&
+       sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt1 >expect &&
        sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual &&
        test_cmp expect actual &&
-       sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt2 >expect &&
+       sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt2 >expect &&
        sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual &&
        test_cmp expect actual
 '
@@ -713,7 +818,7 @@ Cc: cc@example.com,
        two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -759,7 +864,7 @@ Cc: A <author@example.com>,
        two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -796,7 +901,7 @@ Cc: A <author@example.com>,
        C O Mitter <committer@example.com>
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -824,7 +929,7 @@ From: Example <from@example.com>
 To: to@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -860,7 +965,7 @@ Cc: A <author@example.com>,
        cc-cmd@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -893,7 +998,7 @@ Cc: A <author@example.com>,
        two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -926,7 +1031,7 @@ Cc: A <author@example.com>,
        two@example.com
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -963,7 +1068,7 @@ Cc: A <author@example.com>,
        C O Mitter <committer@example.com>
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -993,7 +1098,7 @@ Cc: A <author@example.com>,
        C O Mitter <committer@example.com>
 Subject: [PATCH 1/1] Second.
 Date: DATE-STRING
-Message-Id: MESSAGE-ID-STRING
+Message-ID: MESSAGE-ID-STRING
 X-Mailer: X-MAILER-STRING
 MIME-Version: 1.0
 Content-Transfer-Encoding: 8bit
@@ -1478,7 +1583,7 @@ test_expect_success $PREREQ 'To headers from files reset each patch' '
 test_expect_success $PREREQ 'setup expect' '
 cat >email-using-8bit <<\EOF
 From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-Message-Id: <bogus-message-id@example.com>
+Message-ID: <bogus-message-id@example.com>
 From: author@example.com
 Date: Sat, 12 Jun 2010 15:53:58 +0200
 Subject: subject goes here
@@ -1564,7 +1669,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
 test_expect_success $PREREQ 'setup expect' '
        cat >email-using-8bit <<-\EOF
        From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-       Message-Id: <bogus-message-id@example.com>
+       Message-ID: <bogus-message-id@example.com>
        From: author@example.com
        Date: Sat, 12 Jun 2010 15:53:58 +0200
        Subject: Dieser Betreff enthält auch einen Umlaut!
@@ -1593,7 +1698,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
 test_expect_success $PREREQ 'setup expect' '
        cat >email-using-8bit <<-\EOF
        From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-       Message-Id: <bogus-message-id@example.com>
+       Message-ID: <bogus-message-id@example.com>
        From: A U Thor <author@example.com>
        Date: Sat, 12 Jun 2010 15:53:58 +0200
        Content-Type: text/plain; charset=UTF-8
@@ -1674,7 +1779,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
 test_expect_success $PREREQ 'setup expect' '
        cat >email-using-qp <<-\EOF
        From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-       Message-Id: <bogus-message-id@example.com>
+       Message-ID: <bogus-message-id@example.com>
        From: A U Thor <author@example.com>
        Date: Sat, 12 Jun 2010 15:53:58 +0200
        MIME-Version: 1.0
@@ -1700,7 +1805,7 @@ test_expect_success $PREREQ 'convert from quoted-printable to base64' '
 test_expect_success $PREREQ 'setup expect' "
 tr -d '\\015' | tr '%' '\\015' >email-using-crlf <<EOF
 From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-Message-Id: <bogus-message-id@example.com>
+Message-ID: <bogus-message-id@example.com>
 From: A U Thor <author@example.com>
 Date: Sat, 12 Jun 2010 15:53:58 +0200
 Content-Type: text/plain; charset=UTF-8
@@ -2326,6 +2431,37 @@ test_expect_success $PREREQ 'invoke hook' '
        )
 '
 
+expected_file_counter_output () {
+       total=$1
+       count=0
+       while test $count -ne $total
+       do
+               count=$((count + 1)) &&
+               echo "$count/$total" || return
+       done
+}
+
+test_expect_success $PREREQ '--validate hook allows counting of messages' '
+       test_when_finished "rm -rf my-hooks.log" &&
+       test_config core.hooksPath "my-hooks" &&
+       mkdir -p my-hooks &&
+
+       write_script my-hooks/sendemail-validate <<-\EOF &&
+               num=$GIT_SENDEMAIL_FILE_COUNTER &&
+               tot=$GIT_SENDEMAIL_FILE_TOTAL &&
+               echo "$num/$tot" >>my-hooks.log || exit 1
+       EOF
+
+       >my-hooks.log &&
+       expected_file_counter_output 4 >expect &&
+       git send-email \
+               --from="Example <from@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               --validate -3 --cover-letter --force &&
+       test_cmp expect my-hooks.log
+'
+
 test_expect_success $PREREQ 'test that send-email works outside a repo' '
        nongit git send-email \
                --from="Example <nobody@example.com>" \
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 aa55b41b9a97eaaadf9910ddfd62e0e349d405c8..ac237a1f906b2a05226c4cc7002763813dc543b7 100755 (executable)
@@ -388,9 +388,7 @@ test_expect_success 'B: accept branch name "TEMP_TAG"' '
 
        INPUT_END
 
-       test_when_finished "rm -f .git/TEMP_TAG
-               git gc
-               git prune" &&
+       test_when_finished "rm -f .git/TEMP_TAG && git gc --prune=now" &&
        git fast-import <input &&
        test $(test-tool ref-store main resolve-ref TEMP_TAG 0 | cut -f1 -d " " ) != "$ZERO_OID" &&
        test $(git rev-parse main) = $(git rev-parse TEMP_TAG^)
@@ -406,8 +404,7 @@ test_expect_success 'B: accept empty committer' '
        INPUT_END
 
        test_when_finished "git update-ref -d refs/heads/empty-committer-1
-               git gc
-               git prune" &&
+               git gc --prune=now" &&
        git fast-import <input &&
        out=$(git fsck) &&
        echo "$out" &&
@@ -452,8 +449,7 @@ test_expect_success 'B: accept and fixup committer with no name' '
        INPUT_END
 
        test_when_finished "git update-ref -d refs/heads/empty-committer-2
-               git gc
-               git prune" &&
+               git gc --prune=now" &&
        git fast-import <input &&
        out=$(git fsck) &&
        echo "$out" &&
@@ -1778,8 +1774,7 @@ test_expect_success 'P: verbatim SHA gitlinks' '
        INPUT_END
 
        git branch -D sub &&
-       git gc &&
-       git prune &&
+       git gc --prune=now &&
        git fast-import <input &&
        test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)
 '
index a98ef032d94c106c8f2ee604b60b771e11880f2d..410a871c52af87cd9fe9ab9da5350b032fc5689d 100755 (executable)
@@ -49,4 +49,33 @@ test_expect_success 'import with submodule mapping' '
        test_cmp expect actual
 '
 
+test_expect_success 'paths adjusted for relative subdir' '
+       git init deep-dst &&
+       mkdir deep-dst/subdir &&
+       >deep-dst/subdir/empty-marks &&
+       git -C deep-dst/subdir fast-import \
+               --rewrite-submodules-from=sub:../../from \
+               --rewrite-submodules-to=sub:../../to \
+               --import-marks=empty-marks \
+               --export-marks=exported-marks \
+               --export-pack-edges=exported-edges \
+               <dump &&
+       # we do not bother checking resulting repo; we just care that nothing
+       # complained about failing to open files for reading, and that files
+       # for writing were created in the expected spot
+       test_path_is_file deep-dst/subdir/exported-marks &&
+       test_path_is_file deep-dst/subdir/exported-edges
+'
+
+test_expect_success 'relative marks are not affected by subdir' '
+       git init deep-relative &&
+       mkdir deep-relative/subdir &&
+       git -C deep-relative/subdir fast-import \
+               --relative-marks \
+               --export-marks=exported-marks \
+               <dump &&
+       test_path_is_missing deep-relative/subdir/exported-marks &&
+       test_path_is_file deep-relative/.git/info/fast-import/exported-marks
+'
+
 test_done
index 77047e250dc2c862182619f717b6b96206a38ec7..156a6474847cf6e5bc86df2212ce98211986e6d6 100755 (executable)
@@ -25,6 +25,7 @@ test_expect_success 'setup simple repo' '
 test_expect_success 'export anonymized stream' '
        git fast-export --anonymize --all \
                --anonymize-map=retain-me \
+               --anonymize-map=xyzzy:should-not-appear \
                --anonymize-map=xyzzy:custom-name \
                --anonymize-map=other \
                >stream
@@ -41,6 +42,7 @@ test_expect_success 'stream omits path names' '
 
 test_expect_success 'stream contains user-specified names' '
        grep retain-me stream &&
+       ! grep should-not-appear stream &&
        grep custom-name stream
 '
 
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 dc88d0e064931aab48a3e93002cc67416090282c..a4b3cb94929c9cddfdb5a751f39b42acdb2529ab 100755 (executable)
@@ -330,7 +330,7 @@ test_expect_success 'initial import time from top change time' '
        test_when_finished cleanup_git &&
        (
                cd "$git" &&
-               gittime=$(git show -s --raw --pretty=format:%at HEAD) &&
+               gittime=$(git show -s --pretty=format:%at HEAD) &&
                echo $p4time $gittime &&
                test $p4time = $gittime
        )
index d6c0478d98b85412307a422b142386c180ad030a..47e20fb8b149de244a9336e509b0852b87281000 100755 (executable)
@@ -405,40 +405,40 @@ test_expect_success '__gitdir - remote as argument' '
 
 test_expect_success '__git_dequote - plain unquoted word' '
        __git_dequote unquoted-word &&
-       verbose test unquoted-word = "$dequoted_word"
+       test unquoted-word = "$dequoted_word"
 '
 
 # input:    b\a\c\k\'\\\"s\l\a\s\h\es
 # expected: back'\"slashes
 test_expect_success '__git_dequote - backslash escaped' '
        __git_dequote "b\a\c\k\\'\''\\\\\\\"s\l\a\s\h\es" &&
-       verbose test "back'\''\\\"slashes" = "$dequoted_word"
+       test "back'\''\\\"slashes" = "$dequoted_word"
 '
 
 # input:    sin'gle\' '"quo'ted
 # expected: single\ "quoted
 test_expect_success '__git_dequote - single quoted' '
        __git_dequote "'"sin'gle\\\\' '\\\"quo'ted"'" &&
-       verbose test '\''single\ "quoted'\'' = "$dequoted_word"
+       test '\''single\ "quoted'\'' = "$dequoted_word"
 '
 
 # input:    dou"ble\\" "\"\quot"ed
 # expected: double\ "\quoted
 test_expect_success '__git_dequote - double quoted' '
        __git_dequote '\''dou"ble\\" "\"\quot"ed'\'' &&
-       verbose test '\''double\ "\quoted'\'' = "$dequoted_word"
+       test '\''double\ "\quoted'\'' = "$dequoted_word"
 '
 
 # input: 'open single quote
 test_expect_success '__git_dequote - open single quote' '
        __git_dequote "'\''open single quote" &&
-       verbose test "open single quote" = "$dequoted_word"
+       test "open single quote" = "$dequoted_word"
 '
 
 # input: "open double quote
 test_expect_success '__git_dequote - open double quote' '
        __git_dequote "\"open double quote" &&
-       verbose test "open double quote" = "$dequoted_word"
+       test "open double quote" = "$dequoted_word"
 '
 
 
@@ -616,7 +616,7 @@ test_expect_success '__git_is_configured_remote' '
        test_when_finished "git remote remove remote_2" &&
        git remote add remote_2 git://remote_2 &&
        (
-               verbose __git_is_configured_remote remote_2 &&
+               __git_is_configured_remote remote_2 &&
                test_must_fail __git_is_configured_remote non-existent
        )
 '
@@ -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
@@ -2596,30 +2604,30 @@ test_expect_success 'options with value' '
 test_expect_success 'sourcing the completion script clears cached commands' '
        (
                __git_compute_all_commands &&
-               verbose test -n "$__git_all_commands" &&
+               test -n "$__git_all_commands" &&
                . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
-               verbose test -z "$__git_all_commands"
+               test -z "$__git_all_commands"
        )
 '
 
 test_expect_success 'sourcing the completion script clears cached merge strategies' '
        (
                __git_compute_merge_strategies &&
-               verbose test -n "$__git_merge_strategies" &&
+               test -n "$__git_merge_strategies" &&
                . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
-               verbose test -z "$__git_merge_strategies"
+               test -z "$__git_merge_strategies"
        )
 '
 
 test_expect_success 'sourcing the completion script clears cached --options' '
        (
                __gitcomp_builtin checkout &&
-               verbose test -n "$__gitcomp_builtin_checkout" &&
+               test -n "$__gitcomp_builtin_checkout" &&
                __gitcomp_builtin notes_edit &&
-               verbose test -n "$__gitcomp_builtin_notes_edit" &&
+               test -n "$__gitcomp_builtin_notes_edit" &&
                . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
-               verbose test -z "$__gitcomp_builtin_checkout" &&
-               verbose test -z "$__gitcomp_builtin_notes_edit"
+               test -z "$__gitcomp_builtin_checkout" &&
+               test -z "$__gitcomp_builtin_notes_edit"
        )
 '
 
index d459fae6551bd7b5812f8b76a5faae8ebd4075df..d667dda654e2de7f32d5f7d065f6eac59ca9fdbf 100755 (executable)
@@ -13,10 +13,10 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
 
 actual="$TRASH_DIRECTORY/actual"
-c_red='\\[\\e[31m\\]'
-c_green='\\[\\e[32m\\]'
-c_lblue='\\[\\e[1;34m\\]'
-c_clear='\\[\\e[0m\\]'
+c_red='\001\e[31m\002'
+c_green='\001\e[32m\002'
+c_lblue='\001\e[1;34m\002'
+c_clear='\001\e[0m\002'
 
 test_expect_success 'setup for prompt tests' '
        git init otherrepo &&
index 999d46fafe783134aa921c6316f3f6b0a58c5d7f..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"
@@ -1227,15 +1245,6 @@ test_i18ngrep () {
        return 1
 }
 
-# Call any command "$@" but be more verbose about its
-# failure. This is handy for commands like "test" which do
-# not output anything when they fail.
-verbose () {
-       "$@" && return 0
-       echo >&4 "command failed: $(git rev-parse --sq-quote "$@")"
-       return 1
-}
-
 # Check if the file expected to be empty is indeed empty, and barfs
 # otherwise.
 
@@ -1282,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 62136caee5a961f1eb4569f2a92a2feef97fb18c..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
 }
 
@@ -1041,10 +1045,7 @@ want_trace () {
 # (and we want to make sure we run any cleanup like
 # "set +x").
 test_eval_inner_ () {
-       # Do not add anything extra (including LF) after '$*'
-       eval "
-               want_trace && trace_level_=$(($trace_level_+1)) && set -x
-               $*"
+       eval "$*"
 }
 
 test_eval_ () {
@@ -1069,7 +1070,10 @@ test_eval_ () {
        #     be _inside_ the block to avoid polluting the "set -x" output
        #
 
-       test_eval_inner_ "$@" </dev/null >&3 2>&4
+       # Do not add anything extra (including LF) after '$*'
+       test_eval_inner_ </dev/null >&3 2>&4 "
+               want_trace && trace_level_=$(($trace_level_+1)) && set -x
+               $*"
        {
                test_eval_ret_=$?
                if want_trace
@@ -1086,22 +1090,22 @@ test_eval_ () {
        return $test_eval_ret_
 }
 
+fail_117 () {
+       return 117
+}
+
 test_run_ () {
        test_cleanup=:
        expecting_failure=$2
 
        if test "${GIT_TEST_CHAIN_LINT:-1}" != 0; then
-               # turn off tracing for this test-eval, as it simply creates
-               # confusing noise in the "-x" output
-               trace_tmp=$trace
-               trace=
                # 117 is magic because it is unlikely to match the exit
                # code of other programs
-               if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+               test_eval_inner_ "fail_117 && $1" </dev/null >&3 2>&4
+               if test $? != 117
                then
-                       BUG "broken &&-chain or run-away HERE-DOC: $1"
+                       BUG "broken &&-chain: $1"
                fi
-               trace=$trace_tmp
        fi
 
        setup_malloc_check
@@ -1593,7 +1597,8 @@ then
        BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true"
 fi
 
-if test "${GIT_TEST_CHAIN_LINT:-1}" != 0
+if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 &&
+   test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
 then
        "$PERL_PATH" "$TEST_DIRECTORY/chainlint.pl" "$0" ||
                BUG "lint error (see '?!...!? annotations above)"
diff --git a/tag.c b/tag.c
index dfbcd7fcc244ac2500d41655afac3136758bb331..fc3834db467dc4e83ca0a24da61a3f39048f3ec2 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -1,11 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "environment.h"
 #include "tag.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "tree.h"
 #include "blob.h"
 #include "alloc.h"
 #include "gpg-interface.h"
+#include "hex.h"
 #include "packfile.h"
 
 const char *tag_type = "tag";
@@ -51,15 +54,15 @@ int gpg_verify_tag(const struct object_id *oid, const char *name_to_report,
                return error("%s: cannot verify a non-tag object of type %s.",
                                name_to_report ?
                                name_to_report :
-                               find_unique_abbrev(oid, DEFAULT_ABBREV),
+                               repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV),
                                type_name(type));
 
-       buf = read_object_file(oid, &type, &size);
+       buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (!buf)
                return error("%s: unable to read file.",
                                name_to_report ?
                                name_to_report :
-                               find_unique_abbrev(oid, DEFAULT_ABBREV));
+                               repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
 
        ret = run_gpg_verify(buf, size, flags);
 
@@ -216,7 +219,8 @@ int parse_tag(struct tag *item)
 
        if (item->object.parsed)
                return 0;
-       data = read_object_file(&item->object.oid, &type, &size);
+       data = repo_read_object_file(the_repository, &item->object.oid, &type,
+                                    &size);
        if (!data)
                return error("Could not read %s",
                             oid_to_hex(&item->object.oid));
index e27048f970ba3a22823a0a7eab870c424d2e3e1d..ecdebf1afb0d8465717c18409877fe310f980e46 100644 (file)
@@ -42,7 +42,9 @@
  * file created by its parent.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "path.h"
 #include "tempfile.h"
 #include "sigchain.h"
 
diff --git a/templates/hooks--sendemail-validate.sample b/templates/hooks--sendemail-validate.sample
new file mode 100755 (executable)
index 0000000..640bcf8
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# An example hook script to validate a patch (and/or patch series) before
+# sending it via email.
+#
+# The hook should exit with non-zero status after issuing an appropriate
+# message if it wants to prevent the email(s) from being sent.
+#
+# To enable this hook, rename this file to "sendemail-validate".
+#
+# By default, it will only check that the patch(es) can be applied on top of
+# the default upstream branch without conflicts in a secondary worktree. After
+# validation (successful or not) of the last patch of a series, the worktree
+# will be deleted.
+#
+# The following config variables can be set to change the default remote and
+# remote ref that are used to apply the patches against:
+#
+#   sendemail.validateRemote (default: origin)
+#   sendemail.validateRemoteRef (default: HEAD)
+#
+# Replace the TODO placeholders with appropriate checks according to your
+# needs.
+
+validate_cover_letter () {
+       file="$1"
+       # TODO: Replace with appropriate checks (e.g. spell checking).
+       true
+}
+
+validate_patch () {
+       file="$1"
+       # Ensure that the patch applies without conflicts.
+       git am -3 "$file" || return
+       # TODO: Replace with appropriate checks for this patch
+       # (e.g. checkpatch.pl).
+       true
+}
+
+validate_series () {
+       # TODO: Replace with appropriate checks for the whole series
+       # (e.g. quick build, coding style checks, etc.).
+       true
+}
+
+# main -------------------------------------------------------------------------
+
+if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
+then
+       remote=$(git config --default origin --get sendemail.validateRemote) &&
+       ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
+       worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
+       git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
+       git config --replace-all sendemail.validateWorktree "$worktree"
+else
+       worktree=$(git config --get sendemail.validateWorktree)
+fi || {
+       echo "sendemail-validate: error: failed to prepare worktree" >&2
+       exit 1
+}
+
+unset GIT_DIR GIT_WORK_TREE
+cd "$worktree" &&
+
+if grep -q "^diff --git " "$1"
+then
+       validate_patch "$1"
+else
+       validate_cover_letter "$1"
+fi &&
+
+if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
+then
+       git config --unset-all sendemail.validateWorktree &&
+       trap 'git worktree remove -ff "$worktree"' EXIT &&
+       validate_series
+fi
index 532984569132de11f6f05b561f817817523a3468..1f89ffab4c32bc02b5d955851401628a5b9a540e 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "thread-utils.h"
 
 #if defined(hpux) || defined(__hpux) || defined(_hpux)
index 2a2012eb6d0d4b38c047b570ca06697ffead6dbd..5f9074ad1c0b063a0cb906c2dc6182357adcd5ee 100644 (file)
@@ -1,13 +1,17 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "tmp-objdir.h"
+#include "abspath.h"
 #include "chdir-notify.h"
 #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 efa4e2d8e08fcbcd3bf3dfa7c8364a7c06def5e4..971a68abe84bf02656bf9cd5eab584833f3da9f7 100644 (file)
--- a/trace.c
+++ b/trace.c
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
 #include "quote.h"
+#include "setup.h"
+#include "trace.h"
 
 struct trace_key trace_default_key = { "GIT_TRACE", 0, 0, 0 };
 struct trace_key trace_perf_key = TRACE_KEY_INIT(PERFORMANCE);
diff --git a/trace.h b/trace.h
index b6e35b947005ff1aa57b27648653f51a0b3b2fec..d304d55aa1d706dc3f65bbf15c7b2506bc0e9499 100644 (file)
--- a/trace.h
+++ b/trace.h
@@ -1,7 +1,6 @@
 #ifndef TRACE_H
 #define TRACE_H
 
-#include "git-compat-util.h"
 #include "strbuf.h"
 
 /**
index 279bddf53b4804c9a8f51b453c59f184976cc31e..6dc74dff4c73205d332a227b0caf2497b71f7538 100644 (file)
--- a/trace2.c
+++ b/trace2.c
@@ -1,11 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "json-writer.h"
 #include "quote.h"
+#include "repository.h"
 #include "run-command.h"
 #include "sigchain.h"
 #include "thread-utils.h"
 #include "version.h"
+#include "trace.h"
+#include "trace2.h"
 #include "trace2/tr2_cfg.h"
 #include "trace2/tr2_cmd_name.h"
 #include "trace2/tr2_ctr.h"
@@ -273,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;
@@ -631,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;
@@ -641,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 ec9ac1a6efd3f62b4ccae9db8a9d3ac3ceb1c64a..d96d908bb9df6fddb22e4dbecfa07882049bdf78 100644 (file)
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "strbuf.h"
+#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;
@@ -97,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;
@@ -106,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;
                }
        }
@@ -124,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;
 
@@ -133,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 dd313204f517183ccde962e84b6d4be611adb280..b7b5a869b74bcd02c4157d87212359c7dc47e668 100644 (file)
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "strbuf.h"
 #include "trace2/tr2_cmd_name.h"
 
 #define TR2_ENVVAR_PARENT_NAME "GIT_TRACE2_PARENT_NAME"
index 483ca7c308fa216055c1a6de293a1bfbf9de0bb2..87cf9034fba4b91b4d569ea4013e13f9d19b4aa9 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "thread-utils.h"
 #include "trace2/tr2_tgt.h"
 #include "trace2/tr2_tls.h"
@@ -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 8a21dd29725a074a5f9018d7fd8d01750359baee..5be892cd5cdefa654cfd538ea562c2656d23182e 100644 (file)
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "sigchain.h"
+#include "strbuf.h"
 #include "trace2/tr2_dst.h"
 #include "trace2/tr2_sid.h"
 #include "trace2/tr2_sysenv.h"
index dc6e75ef13151fe011c738f8e3dbe706e24c4773..09c4ef0d17378748ee67a870301f7b086bcf6163 100644 (file)
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hex.h"
+#include "strbuf.h"
 #include "trace2/tr2_tbuf.h"
 #include "trace2/tr2_sid.h"
 
index a380dcf9105e8d7b0022b34508ca384923b2fcd6..f26ec95ab4d867a278e1aacbf337d6eef986355f 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "dir.h"
 #include "tr2_sysenv.h"
@@ -57,7 +57,8 @@ 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)
 {
        int k;
 
index 2498482d9ad82a29b2e734b0d726599d594a20c6..c3b3822ed7e4af449adeb0af9b5e512cefdd4779 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "tr2_tbuf.h"
 
 void tr2_tbuf_local_time(struct tr2_tbuf *tb)
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 16f6332755e0d6497643a32d046459b262c01294..53091781eca5dc788e1f9048b0679aae41e6b11a 100644 (file)
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "json-writer.h"
+#include "repository.h"
 #include "run-command.h"
 #include "version.h"
 #include "trace2/tr2_dst.h"
@@ -476,11 +477,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);
index fbbef68dfc01a546240384fbf12582ccb9d64c54..d25ea131643c0b228280b438d2a38ffcd95f9a0d 100644 (file)
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "repository.h"
 #include "run-command.h"
 #include "quote.h"
 #include "version.h"
@@ -296,10 +297,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,
index adae8032639016a90cca56175e5cd59ea21d4e27..a6f9a8a193e058fc164a8e9bd8dc823b7a317a85 100644 (file)
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "repository.h"
 #include "run-command.h"
 #include "quote.h"
 #include "version.h"
@@ -438,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 04900bb4c3a88cb43e5a79f7d6554e2236e52db8..601c9e5036fb27a7f88957559f03821c2fffa4a2 100644 (file)
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "thread-utils.h"
+#include "trace.h"
 #include "trace2/tr2_tls.h"
 
 /*
index 786762dfd26ffc477dec6317178a51435615ea05..31d0e4d1bd1220ea0c9d9b204223766235d81e07 100644 (file)
@@ -1,8 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "thread-utils.h"
 #include "trace2/tr2_tgt.h"
 #include "trace2/tr2_tls.h"
 #include "trace2/tr2_tmr.h"
+#include "trace.h"
 
 #define MY_MAX(a, b) ((a) > (b) ? (a) : (b))
 #define MY_MIN(a, b) ((a) < (b) ? (a) : (b))
index 0fd5b142a377056d1e45f8dfd1ff6ae7a9c40097..f408f9b058dbbc33b1360cf36e1e023b7bba1a54 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -1,5 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
 #include "string-list.h"
 #include "run-command.h"
 #include "commit.h"
@@ -479,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;
@@ -511,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;
index 3ea7c2bb5ad8c462ae0f54c9466af210bc27d0c2..49811ef176dbc5af5e33fe47cf93cf1f57719f5e 100644 (file)
@@ -1,9 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "transport.h"
 #include "quote.h"
 #include "run-command.h"
 #include "commit.h"
 #include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "repository.h"
 #include "revision.h"
 #include "remote.h"
 #include "string-list.h"
@@ -1081,7 +1086,7 @@ static int push_refs_with_export(struct transport *transport,
                struct object_id oid;
 
                private = apply_refspecs(&data->rs, ref->name);
-               if (private && !get_oid(private, &oid)) {
+               if (private && !repo_get_oid(the_repository, private, &oid)) {
                        strbuf_addf(&buf, "^%s", private);
                        string_list_append_nodup(&revlist_args,
                                                 strbuf_detach(&buf, NULL));
index 77a61a9d7bb06a5cfc7992c6fc4f9f3aa8a8ada5..219af8fd50ed57c0fc0f954965e481b51e7aae72 100644 (file)
@@ -1,5 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "config.h"
+#include "environment.h"
+#include "hex.h"
 #include "transport.h"
 #include "hook.h"
 #include "pkt-line.h"
@@ -10,6 +13,7 @@
 #include "walker.h"
 #include "bundle.h"
 #include "dir.h"
+#include "gettext.h"
 #include "refs.h"
 #include "refspec.h"
 #include "branch.h"
 #include "string-list.h"
 #include "oid-array.h"
 #include "sigchain.h"
+#include "trace2.h"
 #include "transport-internal.h"
 #include "protocol.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "color.h"
 #include "bundle-uri.h"
 
@@ -167,7 +173,8 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
 }
 
 static int fetch_refs_from_bundle(struct transport *transport,
-                              int nr_heads, struct ref **to_fetch)
+                                 int nr_heads UNUSED,
+                                 struct ref **to_fetch UNUSED)
 {
        struct bundle_transport_data *data = transport->data;
        struct strvec extra_index_pack_args = STRVEC_INIT;
@@ -276,8 +283,12 @@ static int connect_setup(struct transport *transport, int for_push)
        }
 
        data->conn = git_connect(data->fd, transport->url,
-                                for_push ? data->options.receivepack :
-                                data->options.uploadpack,
+                                for_push ?
+                                       "git-receive-pack" :
+                                       "git-upload-pack",
+                                for_push ?
+                                       data->options.receivepack :
+                                       data->options.uploadpack,
                                 flags);
 
        return 0;
@@ -307,7 +318,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
        struct git_transport_data *data = transport->data;
        struct ref *refs = NULL;
        struct packet_reader reader;
-       int sid_len;
+       size_t sid_len;
        const char *server_sid;
 
        connect_setup(transport, for_push);
@@ -776,7 +787,8 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count,
 static int measure_abbrev(const struct object_id *oid, int sofar)
 {
        char hex[GIT_MAX_HEXSZ + 1];
-       int w = find_unique_abbrev_r(hex, oid, DEFAULT_ABBREV);
+       int w = repo_find_unique_abbrev_r(the_repository, hex, oid,
+                                         DEFAULT_ABBREV);
 
        return (w < sofar) ? sofar : w;
 }
@@ -911,7 +923,7 @@ static int connect_git(struct transport *transport, const char *name,
 {
        struct git_transport_data *data = transport->data;
        data->conn = git_connect(data->fd, transport->url,
-                                executable, 0);
+                                name, executable, 0);
        fd[0] = data->fd[0];
        fd[1] = data->fd[1];
        return 0;
index 85150f504fbfb9501109d297223f566cc36fe0e5..6393cd9823c01f878000ded305cf621b2b526824 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef TRANSPORT_H
 #define TRANSPORT_H
 
-#include "cache.h"
 #include "run-command.h"
 #include "remote.h"
 #include "list-objects-filter-options.h"
index 69031d7cbae6a88c1fca3242e974d9cd435a4c78..8fc159b86ec02ac54d6c8886351b6c3c0ba058b9 100644 (file)
@@ -1,10 +1,25 @@
 /*
  * Helper functions for tree diff generation
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "hash.h"
 #include "tree.h"
+#include "tree-walk.h"
+
+/*
+ * Some mode bits are also used internally for computations.
+ *
+ * They *must* not overlap with any valid modes, and they *must* not be emitted
+ * to outside world - i.e. appear on disk or network. In other words, it's just
+ * temporary fields, which we internally use, but they have to stay in-house.
+ *
+ * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
+ *   codebase mode is `unsigned int` which is assumed to be at least 32 bits )
+ */
+
+#define S_DIFFTREE_IFXMIN_NEQ  0x80000000
 
 /*
  * internal mode marker, saying a tree entry != entry of tp[imin]
@@ -302,7 +317,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;
index 74f4d710e8f0f28410fae49a6b9c31bf1045e0ca..29ead71be1731c9e6bd94cf348551d5b4fae78e2 100644 (file)
@@ -1,7 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "tree-walk.h"
 #include "dir.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "trace2.h"
 #include "tree.h"
 #include "pathspec.h"
 #include "json-writer.h"
@@ -430,7 +434,7 @@ 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,
@@ -1011,17 +1015,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;
 
@@ -1039,7 +1043,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;
@@ -1050,7 +1054,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) ||
@@ -1143,9 +1147,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;
                }
 
@@ -1157,13 +1161,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
@@ -1199,9 +1203,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;
                }
@@ -1213,16 +1217,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
@@ -1259,7 +1263,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 6305d531503f25cd0b2632914d9aa7ddea55ff8e..74cdceb3fed258eb7216ebec1fe8a86aef0fa264 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef TREE_WALK_H
 #define TREE_WALK_H
 
-#include "cache.h"
+#include "hash-ll.h"
+
+struct index_state;
+struct repository;
 
 #define MAX_TRAVERSE_TREES 8
 
@@ -221,7 +224,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 410e3b477e557f55ad6843e1106567a3fd155557..c745462f968ed11db2cca234c304dedb5b5c23ae 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -1,7 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "cache-tree.h"
+#include "hex.h"
 #include "tree.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "commit.h"
 #include "tag.h"
@@ -30,7 +32,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)
@@ -58,7 +60,7 @@ int read_tree_at(struct repository *r,
                                    oid_to_hex(&entry.oid),
                                    base->buf, entry.path);
 
-                       if (parse_commit(commit))
+                       if (repo_parse_commit(r, commit))
                                die("Invalid commit %s in submodule path %s%s",
                                    oid_to_hex(&entry.oid),
                                    base->buf, entry.path);
@@ -92,14 +94,72 @@ int read_tree(struct repository *r,
        return ret;
 }
 
-int cmp_cache_name_compare(const void *a_, const void *b_)
+int base_name_compare(const char *name1, size_t len1, int mode1,
+                     const char *name2, size_t len2, int mode2)
 {
-       const struct cache_entry *ce1, *ce2;
+       unsigned char c1, c2;
+       size_t len = len1 < len2 ? len1 : len2;
+       int cmp;
+
+       cmp = memcmp(name1, name2, len);
+       if (cmp)
+               return cmp;
+       c1 = name1[len];
+       c2 = name2[len];
+       if (!c1 && S_ISDIR(mode1))
+               c1 = '/';
+       if (!c2 && S_ISDIR(mode2))
+               c2 = '/';
+       return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
+}
+
+/*
+ * df_name_compare() is identical to base_name_compare(), except it
+ * compares conflicting directory/file entries as equal. Note that
+ * while a directory name compares as equal to a regular file, they
+ * then individually compare _differently_ to a filename that has
+ * a dot after the basename (because '\0' < '.' < '/').
+ *
+ * This is used by routines that want to traverse the git namespace
+ * but then handle conflicting entries together when possible.
+ */
+int df_name_compare(const char *name1, size_t len1, int mode1,
+                   const char *name2, size_t len2, int mode2)
+{
+       unsigned char c1, c2;
+       size_t len = len1 < len2 ? len1 : len2;
+       int cmp;
+
+       cmp = memcmp(name1, name2, len);
+       if (cmp)
+               return cmp;
+       /* Directories and files compare equal (same length, same name) */
+       if (len1 == len2)
+               return 0;
+       c1 = name1[len];
+       if (!c1 && S_ISDIR(mode1))
+               c1 = '/';
+       c2 = name2[len];
+       if (!c2 && S_ISDIR(mode2))
+               c2 = '/';
+       if (c1 == '/' && !c2)
+               return 0;
+       if (c2 == '/' && !c1)
+               return 0;
+       return c1 - c2;
+}
 
-       ce1 = *((const struct cache_entry **)a_);
-       ce2 = *((const struct cache_entry **)b_);
-       return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
-                                 ce2->name, ce2->ce_namelen, ce_stage(ce2));
+int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
+{
+       size_t min_len = (len1 < len2) ? len1 : len2;
+       int cmp = memcmp(name1, name2, min_len);
+       if (cmp)
+               return cmp;
+       if (len1 < len2)
+               return -1;
+       if (len1 > len2)
+               return 1;
+       return 0;
 }
 
 struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
@@ -129,7 +189,8 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)
 
        if (item->object.parsed)
                return 0;
-       buffer = read_object_file(&item->object.oid, &type, &size);
+       buffer = repo_read_object_file(the_repository, &item->object.oid,
+                                      &type, &size);
        if (!buffer)
                return quiet_on_missing ? -1 :
                        error("Could not read %s",
diff --git a/tree.h b/tree.h
index 6efff003e2120e3cc5a82cda5bde904bfefa786d..1b5ecbda6b335b4962ee2150534dfd8c0a73964c 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -3,6 +3,7 @@
 
 #include "object.h"
 
+struct pathspec;
 struct repository;
 struct strbuf;
 
@@ -28,7 +29,15 @@ void free_tree_buffer(struct tree *tree);
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const struct object_id *oid);
 
-int cmp_cache_name_compare(const void *a_, const void *b_);
+/*
+ * Functions for comparing pathnames
+ */
+int base_name_compare(const char *name1, size_t len1, int mode1,
+                     const char *name2, size_t len2, int mode2);
+int df_name_compare(const char *name1, size_t len1, int mode1,
+                   const char *name2, size_t len2, int mode2);
+int name_compare(const char *name1, size_t len1,
+                const char *name2, size_t len2);
 
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
index 97c851b27df4a7ea2bc33362a9d2f9dce38c0522..e15fb0455bbd9d6b5fa113ec9bb5cea4f6b6d375 100644 (file)
@@ -94,7 +94,7 @@ static const struct interval zero_width[] = {
 { 0x0E47, 0x0E4E },
 { 0x0EB1, 0x0EB1 },
 { 0x0EB4, 0x0EBC },
-{ 0x0EC8, 0x0ECD },
+{ 0x0EC8, 0x0ECE },
 { 0x0F18, 0x0F19 },
 { 0x0F35, 0x0F35 },
 { 0x0F37, 0x0F37 },
@@ -228,6 +228,7 @@ static const struct interval zero_width[] = {
 { 0x10AE5, 0x10AE6 },
 { 0x10D24, 0x10D27 },
 { 0x10EAB, 0x10EAC },
+{ 0x10EFD, 0x10EFF },
 { 0x10F46, 0x10F50 },
 { 0x10F82, 0x10F85 },
 { 0x11001, 0x11001 },
@@ -252,6 +253,7 @@ static const struct interval zero_width[] = {
 { 0x11234, 0x11234 },
 { 0x11236, 0x11237 },
 { 0x1123E, 0x1123E },
+{ 0x11241, 0x11241 },
 { 0x112DF, 0x112DF },
 { 0x112E3, 0x112EA },
 { 0x11300, 0x11301 },
@@ -313,7 +315,12 @@ static const struct interval zero_width[] = {
 { 0x11D95, 0x11D95 },
 { 0x11D97, 0x11D97 },
 { 0x11EF3, 0x11EF4 },
-{ 0x13430, 0x13438 },
+{ 0x11F00, 0x11F01 },
+{ 0x11F36, 0x11F3A },
+{ 0x11F40, 0x11F40 },
+{ 0x11F42, 0x11F42 },
+{ 0x13430, 0x13440 },
+{ 0x13447, 0x13455 },
 { 0x16AF0, 0x16AF4 },
 { 0x16B30, 0x16B36 },
 { 0x16F4F, 0x16F4F },
@@ -339,9 +346,11 @@ static const struct interval zero_width[] = {
 { 0x1E01B, 0x1E021 },
 { 0x1E023, 0x1E024 },
 { 0x1E026, 0x1E02A },
+{ 0x1E08F, 0x1E08F },
 { 0x1E130, 0x1E136 },
 { 0x1E2AE, 0x1E2AE },
 { 0x1E2EC, 0x1E2EF },
+{ 0x1E4EC, 0x1E4EF },
 { 0x1E8D0, 0x1E8D6 },
 { 0x1E944, 0x1E94A },
 { 0xE0001, 0xE0001 },
@@ -417,7 +426,9 @@ static const struct interval double_width[] = {
 { 0x1AFF5, 0x1AFFB },
 { 0x1AFFD, 0x1AFFE },
 { 0x1B000, 0x1B122 },
+{ 0x1B132, 0x1B132 },
 { 0x1B150, 0x1B152 },
+{ 0x1B155, 0x1B155 },
 { 0x1B164, 0x1B167 },
 { 0x1B170, 0x1B2FB },
 { 0x1F004, 0x1F004 },
@@ -451,7 +462,7 @@ static const struct interval double_width[] = {
 { 0x1F6CC, 0x1F6CC },
 { 0x1F6D0, 0x1F6D2 },
 { 0x1F6D5, 0x1F6D7 },
-{ 0x1F6DD, 0x1F6DF },
+{ 0x1F6DC, 0x1F6DF },
 { 0x1F6EB, 0x1F6EC },
 { 0x1F6F4, 0x1F6FC },
 { 0x1F7E0, 0x1F7EB },
@@ -459,15 +470,13 @@ static const struct interval double_width[] = {
 { 0x1F90C, 0x1F93A },
 { 0x1F93C, 0x1F945 },
 { 0x1F947, 0x1F9FF },
-{ 0x1FA70, 0x1FA74 },
-{ 0x1FA78, 0x1FA7C },
-{ 0x1FA80, 0x1FA86 },
-{ 0x1FA90, 0x1FAAC },
-{ 0x1FAB0, 0x1FABA },
-{ 0x1FAC0, 0x1FAC5 },
-{ 0x1FAD0, 0x1FAD9 },
-{ 0x1FAE0, 0x1FAE7 },
-{ 0x1FAF0, 0x1FAF6 },
+{ 0x1FA70, 0x1FA7C },
+{ 0x1FA80, 0x1FA88 },
+{ 0x1FA90, 0x1FABD },
+{ 0x1FABF, 0x1FAC5 },
+{ 0x1FACE, 0x1FADB },
+{ 0x1FAE0, 0x1FAE8 },
+{ 0x1FAF0, 0x1FAF8 },
 { 0x20000, 0x2FFFD },
 { 0x30000, 0x3FFFD }
 };
index e0be1badb58dee8af8e28c4a4486bf0fdba18a9c..79800d80636fc57fa8cc2696e33013c1c29e86b3 100644 (file)
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "strbuf.h"
 #include "unix-socket.h"
 
 #define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5)
index efa2a207abcd42021fcae682da1d7e5afbc856fa..22ac2373e0788d9a0c7f377b86a756e5ef4ee518 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "lockfile.h"
 #include "unix-socket.h"
 #include "unix-stream-server.h"
index 3d05e45a279b0b0231da5d9a5829c76818af18bd..87517364dc0190acb499ca6d2972e69e1a9fe74e 100644 (file)
@@ -1,8 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "strvec.h"
 #include "repository.h"
 #include "config.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"
 #include "progress.h"
 #include "refs.h"
 #include "attr.h"
+#include "read-cache.h"
 #include "split-index.h"
 #include "sparse-index.h"
 #include "submodule.h"
 #include "submodule-config.h"
+#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"
+#include "setup.h"
 
 /*
  * Error messages expected by scripts out of plumbing commands such as
@@ -66,8 +75,8 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
 };
 
 #define ERRORMSG(o,type) \
-       ( ((o) && (o)->msgs[(type)]) \
-         ? ((o)->msgs[(type)])      \
+       ( ((o) && (o)->internal.msgs[(type)]) \
+         ? ((o)->internal.msgs[(type)])      \
          : (unpack_plumbing_errors[(type)]) )
 
 static const char *super_prefixed(const char *path, const char *super_prefix)
@@ -108,10 +117,10 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                                  const char *cmd)
 {
        int i;
-       const char **msgs = opts->msgs;
+       const char **msgs = opts->internal.msgs;
        const char *msg;
 
-       strvec_init(&opts->msgs_to_free);
+       strvec_init(&opts->internal.msgs_to_free);
 
        if (!strcmp(cmd, "checkout"))
                msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
@@ -129,7 +138,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                          "Please commit your changes or stash them before you %s.")
                      : _("Your local changes to the following files would be overwritten by %s:\n%%s");
        msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] =
-               strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
+               strvec_pushf(&opts->internal.msgs_to_free, msg, cmd, cmd);
 
        msgs[ERROR_NOT_UPTODATE_DIR] =
                _("Updating the following directories would lose untracked files in them:\n%s");
@@ -153,7 +162,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                          "Please move or remove them before you %s.")
                      : _("The following untracked working tree files would be removed by %s:\n%%s");
        msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] =
-               strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
+               strvec_pushf(&opts->internal.msgs_to_free, msg, cmd, cmd);
 
        if (!strcmp(cmd, "checkout"))
                msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE)
@@ -171,7 +180,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                          "Please move or remove them before you %s.")
                      : _("The following untracked working tree files would be overwritten by %s:\n%%s");
        msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] =
-               strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd);
+               strvec_pushf(&opts->internal.msgs_to_free, msg, cmd, cmd);
 
        /*
         * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
@@ -189,16 +198,16 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
        msgs[WARNING_SPARSE_ORPHANED_NOT_OVERWRITTEN] =
                _("The following paths were already present and thus not updated despite sparse patterns:\n%s");
 
-       opts->show_all_errors = 1;
+       opts->internal.show_all_errors = 1;
        /* rejected paths may not have a static buffer */
-       for (i = 0; i < ARRAY_SIZE(opts->unpack_rejects); i++)
-               opts->unpack_rejects[i].strdup_strings = 1;
+       for (i = 0; i < ARRAY_SIZE(opts->internal.unpack_rejects); i++)
+               opts->internal.unpack_rejects[i].strdup_strings = 1;
 }
 
 void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
 {
-       strvec_clear(&opts->msgs_to_free);
-       memset(opts->msgs, 0, sizeof(opts->msgs));
+       strvec_clear(&opts->internal.msgs_to_free);
+       memset(opts->internal.msgs, 0, sizeof(opts->internal.msgs));
 }
 
 static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
@@ -210,7 +219,7 @@ static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
                set |= CE_WT_REMOVE;
 
        ce->ce_flags = (ce->ce_flags & ~clear) | set;
-       return add_index_entry(&o->result, ce,
+       return add_index_entry(&o->internal.result, ce,
                               ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
 }
 
@@ -218,7 +227,7 @@ static void add_entry(struct unpack_trees_options *o,
                      const struct cache_entry *ce,
                      unsigned int set, unsigned int clear)
 {
-       do_add_entry(o, dup_cache_entry(ce, &o->result), set, clear);
+       do_add_entry(o, dup_cache_entry(ce, &o->internal.result), set, clear);
 }
 
 /*
@@ -233,7 +242,7 @@ static int add_rejected_path(struct unpack_trees_options *o,
        if (o->quiet)
                return -1;
 
-       if (!o->show_all_errors)
+       if (!o->internal.show_all_errors)
                return error(ERRORMSG(o, e), super_prefixed(path,
                                                            o->super_prefix));
 
@@ -241,7 +250,7 @@ static int add_rejected_path(struct unpack_trees_options *o,
         * Otherwise, insert in a list for future display by
         * display_(error|warning)_msgs()
         */
-       string_list_append(&o->unpack_rejects[e], path);
+       string_list_append(&o->internal.unpack_rejects[e], path);
        return -1;
 }
 
@@ -253,7 +262,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
        int e;
        unsigned error_displayed = 0;
        for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
-               struct string_list *rejects = &o->unpack_rejects[e];
+               struct string_list *rejects = &o->internal.unpack_rejects[e];
 
                if (rejects->nr > 0) {
                        int i;
@@ -281,7 +290,7 @@ static void display_warning_msgs(struct unpack_trees_options *o)
        unsigned warning_displayed = 0;
        for (e = NB_UNPACK_TREES_ERROR_TYPES + 1;
             e < NB_UNPACK_TREES_WARNING_TYPES; e++) {
-               struct string_list *rejects = &o->unpack_rejects[e];
+               struct string_list *rejects = &o->internal.unpack_rejects[e];
 
                if (rejects->nr > 0) {
                        int i;
@@ -458,7 +467,7 @@ static int check_updates(struct unpack_trees_options *o,
        if (should_update_submodules())
                load_gitmodules_file(index, &state);
 
-       if (has_promisor_remote())
+       if (repo_has_promisor_remote(the_repository))
                /*
                 * Prefetch the objects that are to be checked out in the loop
                 * below.
@@ -600,13 +609,14 @@ static void mark_ce_used(struct cache_entry *ce, struct unpack_trees_options *o)
 {
        ce->ce_flags |= CE_UNPACKED;
 
-       if (o->cache_bottom < o->src_index->cache_nr &&
-           o->src_index->cache[o->cache_bottom] == ce) {
-               int bottom = o->cache_bottom;
+       if (o->internal.cache_bottom < o->src_index->cache_nr &&
+           o->src_index->cache[o->internal.cache_bottom] == ce) {
+               int bottom = o->internal.cache_bottom;
+
                while (bottom < o->src_index->cache_nr &&
                       o->src_index->cache[bottom]->ce_flags & CE_UNPACKED)
                        bottom++;
-               o->cache_bottom = bottom;
+               o->internal.cache_bottom = bottom;
        }
 }
 
@@ -652,7 +662,7 @@ static void mark_ce_used_same_name(struct cache_entry *ce,
 static struct cache_entry *next_cache_entry(struct unpack_trees_options *o)
 {
        const struct index_state *index = o->src_index;
-       int pos = o->cache_bottom;
+       int pos = o->internal.cache_bottom;
 
        while (pos < index->cache_nr) {
                struct cache_entry *ce = index->cache[pos];
@@ -711,7 +721,7 @@ static void restore_cache_bottom(struct traverse_info *info, int bottom)
 
        if (o->diff_index_cached)
                return;
-       o->cache_bottom = bottom;
+       o->internal.cache_bottom = bottom;
 }
 
 static int switch_cache_bottom(struct traverse_info *info)
@@ -721,13 +731,13 @@ static int switch_cache_bottom(struct traverse_info *info)
 
        if (o->diff_index_cached)
                return 0;
-       ret = o->cache_bottom;
+       ret = o->internal.cache_bottom;
        pos = find_cache_pos(info->prev, info->name, info->namelen);
 
        if (pos < -1)
-               o->cache_bottom = -2 - pos;
+               o->internal.cache_bottom = -2 - pos;
        else if (pos < 0)
-               o->cache_bottom = o->src_index->cache_nr;
+               o->internal.cache_bottom = o->src_index->cache_nr;
        return ret;
 }
 
@@ -838,7 +848,7 @@ static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names,
                mark_ce_used(src[0], o);
        }
        free(tree_ce);
-       if (o->debug_unpack)
+       if (o->internal.debug_unpack)
                printf("Unpacked %d entries from %s to %s using cache-tree\n",
                       nr_entries,
                       o->src_index->cache[pos]->name,
@@ -873,9 +883,9 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
                 * save and restore cache_bottom anyway to not miss
                 * unprocessed entries before 'pos'.
                 */
-               bottom = o->cache_bottom;
+               bottom = o->internal.cache_bottom;
                ret = traverse_by_cache_tree(pos, nr_entries, n, info);
-               o->cache_bottom = bottom;
+               o->internal.cache_bottom = bottom;
                return ret;
        }
 
@@ -1212,8 +1222,8 @@ static int unpack_single_entry(int n, unsigned long mask,
                 * cache entry from the index aware logic.
                 */
                src[i + o->merge] = create_ce_entry(info, names + i, stage,
-                                                   &o->result, o->merge,
-                                                   bit & dirmask);
+                                                   &o->internal.result,
+                                                   o->merge, bit & dirmask);
        }
 
        if (o->merge) {
@@ -1237,7 +1247,7 @@ static int unpack_single_entry(int n, unsigned long mask,
 
 static int unpack_failed(struct unpack_trees_options *o, const char *message)
 {
-       discard_index(&o->result);
+       discard_index(&o->internal.result);
        if (!o->quiet && !o->exiting_early) {
                if (message)
                        return error("%s", message);
@@ -1260,7 +1270,7 @@ static int find_cache_pos(struct traverse_info *info,
        struct index_state *index = o->src_index;
        int pfxlen = info->pathlen;
 
-       for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
+       for (pos = o->internal.cache_bottom; pos < index->cache_nr; pos++) {
                const struct cache_entry *ce = index->cache[pos];
                const char *ce_name, *ce_slash;
                int cmp, ce_len;
@@ -1271,8 +1281,8 @@ static int find_cache_pos(struct traverse_info *info,
                         * we can never match it; don't check it
                         * again.
                         */
-                       if (pos == o->cache_bottom)
-                               ++o->cache_bottom;
+                       if (pos == o->internal.cache_bottom)
+                               ++o->internal.cache_bottom;
                        continue;
                }
                if (!ce_in_traverse_path(ce, info)) {
@@ -1450,7 +1460,7 @@ static int unpack_sparse_callback(int n, unsigned long mask, unsigned long dirma
         */
        if (!is_null_oid(&names[0].oid)) {
                src[0] = create_ce_entry(info, &names[0], 0,
-                                       &o->result, 1,
+                                       &o->internal.result, 1,
                                        dirmask & (1ul << 0));
                src[0]->ce_flags |= (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
        }
@@ -1487,7 +1497,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
        while (!p->mode)
                p++;
 
-       if (o->debug_unpack)
+       if (o->internal.debug_unpack)
                debug_unpack_callback(n, mask, dirmask, names, info);
 
        /* Are we supposed to look at the index too? */
@@ -1560,7 +1570,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
                                 * in 'mark_ce_used()'
                                 */
                                if (!src[0] || !S_ISSPARSEDIR(src[0]->ce_mode))
-                                       o->cache_bottom += matches;
+                                       o->internal.cache_bottom += matches;
                                return mask;
                        }
                }
@@ -1809,7 +1819,7 @@ static void populate_from_existing_patterns(struct unpack_trees_options *o,
        if (get_sparse_checkout_patterns(pl) < 0)
                o->skip_sparse_checkout = 1;
        else
-               o->pl = pl;
+               o->internal.pl = pl;
 }
 
 static void update_sparsity_for_prefix(const char *prefix,
@@ -1871,8 +1881,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
        if (len > MAX_UNPACK_TREES)
                die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
-       if (o->dir)
-               BUG("o->dir is for internal use only");
+       if (o->internal.dir)
+               BUG("o->internal.dir is for internal use only");
+       if (o->internal.pl)
+               BUG("o->internal.pl is for internal use only");
+       if (o->df_conflict_entry)
+               BUG("o->df_conflict_entry is an output only field");
 
        trace_performance_enter();
        trace2_region_enter("unpack_trees", "unpack_trees", the_repository);
@@ -1889,9 +1903,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                BUG("UNPACK_RESET_OVERWRITE_UNTRACKED incompatible with preserved ignored files");
 
        if (!o->preserve_ignored) {
-               o->dir = &dir;
-               o->dir->flags |= DIR_SHOW_IGNORED;
-               setup_standard_excludes(o->dir);
+               o->internal.dir = &dir;
+               o->internal.dir->flags |= DIR_SHOW_IGNORED;
+               setup_standard_excludes(o->internal.dir);
        }
 
        if (o->prefix)
@@ -1899,49 +1913,52 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
        if (!core_apply_sparse_checkout || !o->update)
                o->skip_sparse_checkout = 1;
-       if (!o->skip_sparse_checkout && !o->pl) {
+       if (!o->skip_sparse_checkout) {
                memset(&pl, 0, sizeof(pl));
                free_pattern_list = 1;
                populate_from_existing_patterns(o, &pl);
        }
 
-       index_state_init(&o->result, o->src_index->repo);
-       o->result.initialized = 1;
-       o->result.timestamp.sec = o->src_index->timestamp.sec;
-       o->result.timestamp.nsec = o->src_index->timestamp.nsec;
-       o->result.version = o->src_index->version;
+       index_state_init(&o->internal.result, o->src_index->repo);
+       o->internal.result.initialized = 1;
+       o->internal.result.timestamp.sec = o->src_index->timestamp.sec;
+       o->internal.result.timestamp.nsec = o->src_index->timestamp.nsec;
+       o->internal.result.version = o->src_index->version;
        if (!o->src_index->split_index) {
-               o->result.split_index = NULL;
+               o->internal.result.split_index = NULL;
        } else if (o->src_index == o->dst_index) {
                /*
                 * o->dst_index (and thus o->src_index) will be discarded
-                * and overwritten with o->result at the end of this function,
-                * so just use src_index's split_index to avoid having to
-                * create a new one.
+                * and overwritten with o->internal.result at the end of
+                * this function, so just use src_index's split_index to
+                * avoid having to create a new one.
                 */
-               o->result.split_index = o->src_index->split_index;
-               o->result.split_index->refcount++;
+               o->internal.result.split_index = o->src_index->split_index;
+               if (o->src_index->cache_changed & SPLIT_INDEX_ORDERED)
+                       o->internal.result.cache_changed |= SPLIT_INDEX_ORDERED;
+               o->internal.result.split_index->refcount++;
        } else {
-               o->result.split_index = init_split_index(&o->result);
+               o->internal.result.split_index =
+                       init_split_index(&o->internal.result);
        }
-       oidcpy(&o->result.oid, &o->src_index->oid);
-       o->merge_size = len;
+       oidcpy(&o->internal.result.oid, &o->src_index->oid);
+       o->internal.merge_size = len;
        mark_all_ce_unused(o->src_index);
 
-       o->result.fsmonitor_last_update =
+       o->internal.result.fsmonitor_last_update =
                xstrdup_or_null(o->src_index->fsmonitor_last_update);
-       o->result.fsmonitor_has_run_once = o->src_index->fsmonitor_has_run_once;
+       o->internal.result.fsmonitor_has_run_once = o->src_index->fsmonitor_has_run_once;
 
        if (!o->src_index->initialized &&
            !repo->settings.command_requires_full_index &&
-           is_sparse_index_allowed(&o->result, 0))
-               o->result.sparse_index = 1;
+           is_sparse_index_allowed(&o->internal.result, 0))
+               o->internal.result.sparse_index = 1;
 
        /*
         * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
         */
        if (!o->skip_sparse_checkout)
-               mark_new_skip_worktree(o->pl, o->src_index, 0,
+               mark_new_skip_worktree(o->internal.pl, o->src_index, 0,
                                       CE_NEW_SKIP_WORKTREE, o->verbose_update);
 
        if (!dfc)
@@ -1955,7 +1972,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                setup_traverse_info(&info, prefix);
                info.fn = unpack_callback;
                info.data = o;
-               info.show_all_errors = o->show_all_errors;
+               info.show_all_errors = o->internal.show_all_errors;
                info.pathspec = o->pathspec;
 
                if (o->prefix) {
@@ -1996,7 +2013,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        }
        mark_all_ce_unused(o->src_index);
 
-       if (o->trivial_merges_only && o->nontrivial_merge) {
+       if (o->trivial_merges_only && o->internal.nontrivial_merge) {
                ret = unpack_failed(o, "Merge requires file-level merging");
                goto done;
        }
@@ -2007,13 +2024,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                 * If they will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
                 * so apply_sparse_checkout() won't attempt to remove it from worktree
                 */
-               mark_new_skip_worktree(o->pl, &o->result,
+               mark_new_skip_worktree(o->internal.pl, &o->internal.result,
                                       CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE,
                                       o->verbose_update);
 
                ret = 0;
-               for (i = 0; i < o->result.cache_nr; i++) {
-                       struct cache_entry *ce = o->result.cache[i];
+               for (i = 0; i < o->internal.result.cache_nr; i++) {
+                       struct cache_entry *ce = o->internal.result.cache[i];
 
                        /*
                         * Entries marked with CE_ADDED in merged_entry() do not have
@@ -2027,7 +2044,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                            verify_absent(ce, WARNING_SPARSE_ORPHANED_NOT_OVERWRITTEN, o))
                                ret = 1;
 
-                       if (apply_sparse_checkout(&o->result, ce, o))
+                       if (apply_sparse_checkout(&o->internal.result, ce, o))
                                ret = 1;
                }
                if (ret == 1) {
@@ -2035,46 +2052,47 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                         * Inability to sparsify or de-sparsify individual
                         * paths is not an error, but just a warning.
                         */
-                       if (o->show_all_errors)
+                       if (o->internal.show_all_errors)
                                display_warning_msgs(o);
                        ret = 0;
                }
        }
 
-       ret = check_updates(o, &o->result) ? (-2) : 0;
+       ret = check_updates(o, &o->internal.result) ? (-2) : 0;
        if (o->dst_index) {
-               move_index_extensions(&o->result, o->src_index);
+               move_index_extensions(&o->internal.result, o->src_index);
                if (!ret) {
                        if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
-                               cache_tree_verify(the_repository, &o->result);
+                               cache_tree_verify(the_repository,
+                                                 &o->internal.result);
                        if (!o->skip_cache_tree_update &&
-                           !cache_tree_fully_valid(o->result.cache_tree))
-                               cache_tree_update(&o->result,
+                           !cache_tree_fully_valid(o->internal.result.cache_tree))
+                               cache_tree_update(&o->internal.result,
                                                  WRITE_TREE_SILENT |
                                                  WRITE_TREE_REPAIR);
                }
 
-               o->result.updated_workdir = 1;
+               o->internal.result.updated_workdir = 1;
                discard_index(o->dst_index);
-               *o->dst_index = o->result;
+               *o->dst_index = o->internal.result;
        } else {
-               discard_index(&o->result);
+               discard_index(&o->internal.result);
        }
        o->src_index = NULL;
 
 done:
        if (free_pattern_list)
                clear_pattern_list(&pl);
-       if (o->dir) {
-               dir_clear(o->dir);
-               o->dir = NULL;
+       if (o->internal.dir) {
+               dir_clear(o->internal.dir);
+               o->internal.dir = NULL;
        }
        trace2_region_leave("unpack_trees", "unpack_trees", the_repository);
        trace_performance_leave("unpack_trees");
        return ret;
 
 return_failed:
-       if (o->show_all_errors)
+       if (o->internal.show_all_errors)
                display_error_msgs(o);
        mark_all_ce_unused(o->src_index);
        ret = unpack_failed(o, NULL);
@@ -2089,16 +2107,17 @@ return_failed:
  *
  * CE_NEW_SKIP_WORKTREE is used internally.
  */
-enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
+enum update_sparsity_result update_sparsity(struct unpack_trees_options *o,
+                                           struct pattern_list *pl)
 {
        enum update_sparsity_result ret = UPDATE_SPARSITY_SUCCESS;
-       struct pattern_list pl;
        int i;
        unsigned old_show_all_errors;
        int free_pattern_list = 0;
 
-       old_show_all_errors = o->show_all_errors;
-       o->show_all_errors = 1;
+       old_show_all_errors = o->internal.show_all_errors;
+       o->internal.show_all_errors = 1;
+       index_state_init(&o->internal.result, o->src_index->repo);
 
        /* Sanity checks */
        if (!o->update || o->index_only || o->skip_sparse_checkout)
@@ -2109,20 +2128,19 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
        trace_performance_enter();
 
        /* If we weren't given patterns, use the recorded ones */
-       if (!o->pl) {
-               memset(&pl, 0, sizeof(pl));
+       if (!pl) {
                free_pattern_list = 1;
-               populate_from_existing_patterns(o, &pl);
-               if (o->skip_sparse_checkout)
-                       goto skip_sparse_checkout;
+               pl = xcalloc(1, sizeof(*pl));
+               populate_from_existing_patterns(o, pl);
        }
+       o->internal.pl = pl;
 
        /* Expand sparse directories as needed */
-       expand_index(o->src_index, o->pl);
+       expand_index(o->src_index, o->internal.pl);
 
        /* Set NEW_SKIP_WORKTREE on existing entries. */
        mark_all_ce_unused(o->src_index);
-       mark_new_skip_worktree(o->pl, o->src_index, 0,
+       mark_new_skip_worktree(o->internal.pl, o->src_index, 0,
                               CE_NEW_SKIP_WORKTREE, o->verbose_update);
 
        /* Then loop over entries and update/remove as needed */
@@ -2142,14 +2160,16 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
                        ret = UPDATE_SPARSITY_WARNINGS;
        }
 
-skip_sparse_checkout:
        if (check_updates(o, o->src_index))
                ret = UPDATE_SPARSITY_WORKTREE_UPDATE_FAILURES;
 
        display_warning_msgs(o);
-       o->show_all_errors = old_show_all_errors;
-       if (free_pattern_list)
-               clear_pattern_list(&pl);
+       o->internal.show_all_errors = old_show_all_errors;
+       if (free_pattern_list) {
+               clear_pattern_list(pl);
+               free(pl);
+               o->internal.pl = NULL;
+       }
        trace_performance_leave("update_sparsity");
        return ret;
 }
@@ -2244,15 +2264,15 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,
 }
 
 /*
- * TODO: We should actually invalidate o->result, not src_index [1].
+ * TODO: We should actually invalidate o->internal.result, not src_index [1].
  * But since cache tree and untracked cache both are not copied to
- * o->result until unpacking is complete, we invalidate them on
+ * o->internal.result until unpacking is complete, we invalidate them on
  * src_index instead with the assumption that they will be copied to
  * dst_index at the end.
  *
  * [1] src_index->cache_tree is also used in unpack_callback() so if
- * we invalidate o->result, we need to update it to use
- * o->result.cache_tree as well.
+ * we invalidate o->internal.result, we need to update it to use
+ * o->internal.result.cache_tree as well.
  */
 static void invalidate_ce_path(const struct cache_entry *ce,
                               struct unpack_trees_options *o)
@@ -2336,8 +2356,8 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
        pathbuf = xstrfmt("%.*s/", namelen, ce->name);
 
        memset(&d, 0, sizeof(d));
-       if (o->dir)
-               d.exclude_per_dir = o->dir->exclude_per_dir;
+       if (o->internal.dir)
+               setup_standard_excludes(&d);
        i = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);
        dir_clear(&d);
        free(pathbuf);
@@ -2391,8 +2411,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
        if (ignore_case && icase_exists(o, name, len, st))
                return 0;
 
-       if (o->dir &&
-           is_excluded(o->dir, o->src_index, name, &dtype))
+       if (o->internal.dir &&
+           is_excluded(o->internal.dir, o->src_index, name, &dtype))
                /*
                 * ce->name is explicitly excluded, so it is Ok to
                 * overwrite it.
@@ -2420,7 +2440,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
         * delete this path, which is in a subdirectory that
         * is being replaced with a blob.
         */
-       result = index_file_exists(&o->result, name, len, 0);
+       result = index_file_exists(&o->internal.result, name, len, 0);
        if (result) {
                if (result->ce_flags & CE_REMOVE)
                        return 0;
@@ -2521,7 +2541,7 @@ static int merged_entry(const struct cache_entry *ce,
                        struct unpack_trees_options *o)
 {
        int update = CE_UPDATE;
-       struct cache_entry *merge = dup_cache_entry(ce, &o->result);
+       struct cache_entry *merge = dup_cache_entry(ce, &o->internal.result);
 
        if (!old) {
                /*
@@ -2616,7 +2636,7 @@ static int merged_sparse_dir(const struct cache_entry * const *src, int n,
        setup_traverse_info(&info, src[0]->name);
        info.fn = unpack_sparse_callback;
        info.data = o;
-       info.show_all_errors = o->show_all_errors;
+       info.show_all_errors = o->internal.show_all_errors;
        info.pathspec = o->pathspec;
 
        /* Get the tree descriptors of the sparse directory in each of the merging trees */
@@ -2834,7 +2854,7 @@ int threeway_merge(const struct cache_entry * const *stages,
                        return -1;
        }
 
-       o->nontrivial_merge = 1;
+       o->internal.nontrivial_merge = 1;
 
        /* #2, #3, #4, #6, #7, #9, #10, #11. */
        count = 0;
@@ -2875,9 +2895,9 @@ int twoway_merge(const struct cache_entry * const *src,
        const struct cache_entry *oldtree = src[1];
        const struct cache_entry *newtree = src[2];
 
-       if (o->merge_size != 2)
+       if (o->internal.merge_size != 2)
                return error("Cannot do a twoway merge of %d trees",
-                            o->merge_size);
+                            o->internal.merge_size);
 
        if (oldtree == o->df_conflict_entry)
                oldtree = NULL;
@@ -2957,9 +2977,9 @@ int bind_merge(const struct cache_entry * const *src,
        const struct cache_entry *old = src[0];
        const struct cache_entry *a = src[1];
 
-       if (o->merge_size != 1)
+       if (o->internal.merge_size != 1)
                return error("Cannot do a bind merge of %d trees",
-                            o->merge_size);
+                            o->internal.merge_size);
        if (a && old)
                return o->quiet ? -1 :
                        error(ERRORMSG(o, ERROR_BIND_OVERLAP),
@@ -2983,9 +3003,9 @@ int oneway_merge(const struct cache_entry * const *src,
        const struct cache_entry *old = src[0];
        const struct cache_entry *a = src[1];
 
-       if (o->merge_size != 1)
+       if (o->internal.merge_size != 1)
                return error("Cannot do a oneway merge of %d trees",
-                            o->merge_size);
+                            o->internal.merge_size);
 
        if (!a || a == o->df_conflict_entry)
                return deleted_entry(old, old, o);
@@ -3020,8 +3040,8 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
        const struct cache_entry *worktree = src[1];
        const struct cache_entry *untracked = src[2];
 
-       if (o->merge_size != 2)
-               BUG("invalid merge_size: %d", o->merge_size);
+       if (o->internal.merge_size != 2)
+               BUG("invalid merge_size: %d", o->internal.merge_size);
 
        if (worktree && untracked)
                return error(_("worktree and untracked commit have duplicate entries: %s"),
index 3a7b3e5f0077938f1e28de5f41a691191c098744..9b827c307f6d565fe6becf25839f45f81340b8ce 100644 (file)
@@ -1,7 +1,8 @@
 #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"
@@ -59,47 +60,54 @@ struct unpack_trees_options {
                     preserve_ignored,
                     clone,
                     index_only,
-                    nontrivial_merge,
                     trivial_merges_only,
                     verbose_update,
                     aggressive,
                     skip_unmerged,
                     initial_checkout,
                     diff_index_cached,
-                    debug_unpack,
                     skip_sparse_checkout,
                     quiet,
                     exiting_early,
-                    show_all_errors,
                     dry_run,
                     skip_cache_tree_update;
        enum unpack_trees_reset_type reset;
        const char *prefix;
        const char *super_prefix;
-       int cache_bottom;
        struct pathspec *pathspec;
        merge_fn_t fn;
-       const char *msgs[NB_UNPACK_TREES_WARNING_TYPES];
-       struct strvec msgs_to_free;
-       /*
-        * Store error messages in an array, each case
-        * corresponding to a error message type
-        */
-       struct string_list unpack_rejects[NB_UNPACK_TREES_WARNING_TYPES];
 
        int head_idx;
-       int merge_size;
 
-       struct cache_entry *df_conflict_entry;
+       struct cache_entry *df_conflict_entry; /* output only */
        void *unpack_data;
 
        struct index_state *dst_index;
        struct index_state *src_index;
-       struct index_state result;
 
-       struct pattern_list *pl; /* for internal use */
-       struct dir_struct *dir; /* for internal use only */
        struct checkout_metadata meta;
+
+       struct unpack_trees_options_internal {
+               unsigned int nontrivial_merge,
+                            show_all_errors,
+                            debug_unpack; /* used by read-tree debugging */
+
+               int merge_size; /* used by read-tree debugging */
+               int cache_bottom;
+               const char *msgs[NB_UNPACK_TREES_WARNING_TYPES];
+               struct strvec msgs_to_free;
+
+               /*
+                * Store error messages in an array, each case
+                * corresponding to a error message type
+                */
+               struct string_list unpack_rejects[NB_UNPACK_TREES_WARNING_TYPES];
+
+               struct index_state result;
+
+               struct pattern_list *pl;
+               struct dir_struct *dir;
+       } internal;
 };
 
 int unpack_trees(unsigned n, struct tree_desc *t,
@@ -112,7 +120,8 @@ enum update_sparsity_result {
        UPDATE_SPARSITY_WORKTREE_UPDATE_FAILURES = -2
 };
 
-enum update_sparsity_result update_sparsity(struct unpack_trees_options *options);
+enum update_sparsity_result update_sparsity(struct unpack_trees_options *options,
+                                           struct pattern_list *pl);
 
 int verify_uptodate(const struct cache_entry *ce,
                    struct unpack_trees_options *o);
index 551f22ffa5d63ceabbf5909ee1926b8471722920..94751477ab2d1e1ee28c291d3b1aaaa75e5fe3d4 100644 (file)
@@ -1,10 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
 #include "refs.h"
 #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"
 #include "commit.h"
@@ -19,6 +23,7 @@
 #include "version.h"
 #include "string-list.h"
 #include "strvec.h"
+#include "trace2.h"
 #include "prio-queue.h"
 #include "protocol.h"
 #include "quote.h"
@@ -27,6 +32,7 @@
 #include "commit-graph.h"
 #include "commit-reach.h"
 #include "shallow.h"
+#include "write-or-die.h"
 
 /* Remember to update object flag allocation in object.h */
 #define THEY_HAVE      (1u << 11)
@@ -62,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;
@@ -113,13 +119,14 @@ struct upload_pack_data {
        unsigned allow_ref_in_want : 1;                         /* v2 only */
        unsigned allow_sideband_all : 1;                        /* v2 only */
        unsigned advertise_sid : 1;
+       unsigned sent_capabilities : 1;
 };
 
 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;
@@ -154,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);
@@ -499,8 +506,8 @@ static int got_oid(struct upload_pack_data *data,
 {
        if (get_oid_hex(hex, oid))
                die("git upload-pack: expected SHA1 object, got '%s'", hex);
-       if (!has_object_file_with_flags(oid,
-                                       OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
+       if (!repo_has_object_file_with_flags(the_repository, oid,
+                                            OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
                return -1;
        return do_got_oid(data, oid);
 }
@@ -594,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);
 }
 
 /*
@@ -847,7 +879,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,
@@ -1063,7 +1095,7 @@ static void receive_needs(struct upload_pack_data *data,
                const char *features;
                struct object_id oid_buf;
                const char *arg;
-               int feature_len;
+               size_t feature_len;
 
                reset_timeout(data->timeout);
                if (packet_reader_read(reader) != PACKET_READ_NORMAL)
@@ -1162,7 +1194,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);
 
@@ -1199,18 +1231,17 @@ static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) {
                strbuf_addf(buf, " session-id=%s", trace2_session_id());
 }
 
-static int send_ref(const char *refname, const struct object_id *oid,
-                   int flag UNUSED, void *cb_data)
+static void write_v0_ref(struct upload_pack_data *data,
+                       const char *refname, const char *refname_nons,
+                       const struct object_id *oid)
 {
        static const char *capabilities = "multi_ack thin-pack side-band"
                " side-band-64k ofs-delta shallow deepen-since deepen-not"
                " deepen-relative no-progress include-tag multi_ack_detailed";
-       const char *refname_nons = strip_namespace(refname);
        struct object_id peeled;
-       struct upload_pack_data *data = cb_data;
 
        if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs))
-               return 0;
+               return;
 
        if (capabilities) {
                struct strbuf symref_info = STRBUF_INIT;
@@ -1233,12 +1264,20 @@ static int send_ref(const char *refname, const struct object_id *oid,
                             git_user_agent_sanitized());
                strbuf_release(&symref_info);
                strbuf_release(&session_id);
+               data->sent_capabilities = 1;
        } else {
                packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);
        }
        capabilities = NULL;
        if (!peel_iterated_oid(oid, &peeled))
                packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
+       return;
+}
+
+static int send_ref(const char *refname, const struct object_id *oid,
+                   int flag UNUSED, void *cb_data)
+{
+       write_v0_ref(cb_data, refname, strip_namespace(refname), oid);
        return 0;
 }
 
@@ -1260,7 +1299,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;
@@ -1287,14 +1327,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;
 
@@ -1314,7 +1357,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)) {
@@ -1329,13 +1372,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;
 
@@ -1371,7 +1416,11 @@ 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());
+               }
                /*
                 * fflush stdout before calling advertise_shallow_grafts because send_ref
                 * uses stdio.
@@ -1381,7 +1430,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) {
@@ -1446,7 +1495,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;
@@ -1600,8 +1649,8 @@ static int process_haves(struct upload_pack_data *data, struct oid_array *common
        for (i = 0; i < data->haves.nr; i++) {
                const struct object_id *oid = &data->haves.oid[i];
 
-               if (!has_object_file_with_flags(oid,
-                                               OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
+               if (!repo_has_object_file_with_flags(the_repository, oid,
+                                                    OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
                        continue;
 
                oid_array_append(common, oid);
@@ -1699,7 +1748,7 @@ enum fetch_state {
        FETCH_DONE,
 };
 
-int upload_pack_v2(struct repository *r, struct packet_reader *request)
+int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
 {
        enum fetch_state state = FETCH_PROCESS_ARGS;
        struct upload_pack_data data;
@@ -1775,26 +1824,26 @@ int upload_pack_advertise(struct repository *r,
 
                strbuf_addstr(value, "shallow wait-for-done");
 
-               if (!repo_config_get_bool(the_repository,
+               if (!repo_config_get_bool(r,
                                         "uploadpack.allowfilter",
                                         &allow_filter_value) &&
                    allow_filter_value)
                        strbuf_addstr(value, " filter");
 
-               if (!repo_config_get_bool(the_repository,
+               if (!repo_config_get_bool(r,
                                         "uploadpack.allowrefinwant",
                                         &allow_ref_in_want) &&
                    allow_ref_in_want)
                        strbuf_addstr(value, " ref-in-want");
 
                if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
-                   (!repo_config_get_bool(the_repository,
+                   (!repo_config_get_bool(r,
                                           "uploadpack.allowsidebandall",
                                           &allow_sideband_all_value) &&
                     allow_sideband_all_value))
                        strbuf_addstr(value, " sideband-all");
 
-               if (!repo_config_get_string(the_repository,
+               if (!repo_config_get_string(r,
                                            "uploadpack.blobpackfileuri",
                                            &str) &&
                    str) {
diff --git a/url.c b/url.c
index e04bd60b6bead493e3236949b5b4a837c729c146..2e1a9f6feec96b055a9415748eb721937461c07f 100644 (file)
--- a/url.c
+++ b/url.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hex.h"
+#include "strbuf.h"
 #include "url.h"
 
 int is_urlschemechar(int first_flag, int ch)
index 620a648efc5e81ac8b233153ae504ba145d6ee8f..1c45f23adf2c2fe770c147e9bbf0d5a557fcf688 100644 (file)
@@ -1,4 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "strbuf.h"
 #include "urlmatch.h"
 
 #define URL_ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
@@ -548,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;
@@ -562,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, '.');
@@ -606,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 5a7c6c346c14ca1fb03b99b8ee36574226cf3fd4..09f0ed509b79c5a162f06a7f4cb5c5296d36be56 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -4,7 +4,8 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "git-compat-util.h"
-#include "cache.h"
+#include "gettext.h"
+#include "trace2.h"
 
 static void vreportf(const char *prefix, const char *err, va_list params)
 {
index 58a3d59ef8f471b9c6ffc34cad10e56689c3354c..e399543823bdf2c0c8f24fb87f7622ac4d8a366b 100644 (file)
@@ -1,7 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "userdiff.h"
 #include "attr.h"
+#include "strbuf.h"
 
 static struct userdiff_driver *drivers;
 static int ndrivers;
@@ -15,6 +16,7 @@ static int drivers_alloc;
                .cflags = REG_EXTENDED, \
        }, \
        .word_regex = wrx "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+", \
+       .word_regex_multi_byte = wrx "|[^[:space:]]", \
 }
 #define IPATTERN(lang, rx, wrx) { \
        .name = lang, \
@@ -24,6 +26,7 @@ static int drivers_alloc;
                .cflags = REG_EXTENDED | REG_ICASE, \
        }, \
        .word_regex = wrx "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+", \
+       .word_regex_multi_byte = wrx "|[^[:space:]]", \
 }
 
 /*
@@ -292,7 +295,7 @@ PATTERNS("scheme",
         /* All other words should be delimited by spaces or parentheses */
         "|([^][)(}{[ \t])+"),
 PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
-        "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
+        "\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"),
 { "default", NULL, NULL, -1, { NULL, 0 } },
 };
 #undef PATTERNS
@@ -328,6 +331,25 @@ static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver,
        return 0;
 }
 
+static int regexec_supports_multi_byte_chars(void)
+{
+       static const char not_space[] = "[^[:space:]]";
+       static const char utf8_multi_byte_char[] = "\xc2\xa3";
+       regex_t re;
+       regmatch_t match;
+       static int result = -1;
+
+       if (result != -1)
+               return result;
+       if (regcomp(&re, not_space, REG_EXTENDED))
+               BUG("invalid regular expression: %s", not_space);
+       result = !regexec(&re, utf8_multi_byte_char, 1, &match, 0) &&
+               match.rm_so == 0 &&
+               match.rm_eo == strlen(utf8_multi_byte_char);
+       regfree(&re);
+       return result;
+}
+
 static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t len)
 {
        struct find_by_namelen_data udcbdata = {
@@ -403,7 +425,13 @@ int userdiff_config(const char *k, const char *v)
 struct userdiff_driver *userdiff_find_by_name(const char *name)
 {
        int len = strlen(name);
-       return userdiff_find_by_namelen(name, len);
+       struct userdiff_driver *driver = userdiff_find_by_namelen(name, len);
+       if (driver && driver->word_regex_multi_byte) {
+               if (regexec_supports_multi_byte_chars())
+                       driver->word_regex = driver->word_regex_multi_byte;
+               driver->word_regex_multi_byte = NULL;
+       }
+       return driver;
 }
 
 struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
@@ -415,7 +443,7 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
                check = attr_check_initl("diff", NULL);
        if (!path)
                return NULL;
-       git_check_attr(istate, NULL, path, check);
+       git_check_attr(istate, path, check);
 
        if (ATTR_TRUE(check->items[0].value))
                return &driver_true;
index 24419db6973f5cd9bdfc6b9f300d5ce472c15cfd..d726804c3e5ee8879ff41d5a424569f9e1b10e3d 100644 (file)
@@ -18,6 +18,7 @@ struct userdiff_driver {
        int binary;
        struct userdiff_funcname funcname;
        const char *word_regex;
+       const char *word_regex_multi_byte;
        const char *textconv;
        struct notes_cache *textconv_cache;
        int textconv_want_cache;
index 069ee94a4d79422ea659a7ebe3923662f0626afa..45e676cbca6314d1b65c11e76f754898f060dfda 100644 (file)
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
+#include "strbuf.h"
 #include "string-list.h"
+#include "versioncmp.h"
 
 /*
  * versioncmp(): copied from string/strverscmp.c in glibc commit
@@ -160,15 +162,21 @@ int versioncmp(const char *s1, const char *s2)
        }
 
        if (!initialized) {
-               const struct string_list *deprecated_prereleases;
+               const char *const newk = "versionsort.suffix";
+               const char *const oldk = "versionsort.prereleasesuffix";
+               const struct string_list *newl;
+               const struct string_list *oldl;
+               int new = git_config_get_string_multi(newk, &newl);
+               int old = git_config_get_string_multi(oldk, &oldl);
+
+               if (!new && !old)
+                       warning("ignoring %s because %s is set", oldk, newk);
+               if (!new)
+                       prereleases = newl;
+               else if (!old)
+                       prereleases = oldl;
+
                initialized = 1;
-               prereleases = git_config_get_value_multi("versionsort.suffix");
-               deprecated_prereleases = git_config_get_value_multi("versionsort.prereleasesuffix");
-               if (prereleases) {
-                       if (deprecated_prereleases)
-                               warning("ignoring versionsort.prereleasesuffix because versionsort.suffix is set");
-               } else
-                       prereleases = deprecated_prereleases;
        }
        if (prereleases && swap_prereleases(s1, s2, (const char *) p1 - s1 - 1,
                                            &diff))
diff --git a/versioncmp.h b/versioncmp.h
new file mode 100644 (file)
index 0000000..879b510
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef VERSIONCMP_H
+#define VERSIONCMP_H
+
+int versioncmp(const char *s1, const char *s2);
+
+#endif /* VERSIONCMP_H */
index 99d0e0eae047410660f0bf3b0d3f487d45c1134d..65002a7220adc2e60aafe6a29555df1cee167ad0 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -1,8 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "gettext.h"
+#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"
@@ -79,7 +82,7 @@ static int process_commit(struct walker *walker, struct commit *commit)
 {
        struct commit_list *parents;
 
-       if (parse_commit(commit))
+       if (repo_parse_commit(the_repository, commit))
                return -1;
 
        while (complete && complete->item->date >= commit->date) {
@@ -93,7 +96,7 @@ static int process_commit(struct walker *walker, struct commit *commit)
 
        walker_say(walker, "walk %s\n", oid_to_hex(&commit->object.oid));
 
-       if (process(walker, &get_commit_tree(commit)->object))
+       if (process(walker, &repo_get_commit_tree(the_repository, commit)->object))
                return -1;
 
        for (parents = commit->parents; parents; parents = parents->next) {
@@ -145,7 +148,7 @@ static int process(struct walker *walker, struct object *obj)
                return 0;
        obj->flags |= SEEN;
 
-       if (has_object_file(&obj->oid)) {
+       if (repo_has_object_file(the_repository, &obj->oid)) {
                /* We already have it, so we should scan it now. */
                obj->flags |= TO_SCAN;
        }
index 7e5a7ea1eaa9d9d49219537b70256f1d947633ea..8ea29141bd7c5233a25c89aa55ceeafcf7e7529d 100644 (file)
@@ -9,11 +9,15 @@
 **  work differently than '*', and to fix the character-class code.
 */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "wildmatch.h"
 
 typedef unsigned char uchar;
 
+/* Internal return values */
+#define WM_ABORT_ALL -1
+#define WM_ABORT_TO_STARSTAR -2
+
 /* What character marks an inverted character class? */
 #define NEGATE_CLASS   '!'
 #define NEGATE_CLASS2  '^'
@@ -83,12 +87,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
                        continue;
                case '*':
                        if (*++p == '*') {
-                               const uchar *prev_p = p - 2;
+                               const uchar *prev_p = p;
                                while (*++p == '*') {}
                                if (!(flags & WM_PATHNAME))
                                        /* without WM_PATHNAME, '*' == '**' */
                                        match_slash = 1;
-                               else if ((prev_p < pattern || *prev_p == '/') &&
+                               else if ((prev_p - pattern < 2 || *(prev_p - 2) == '/') &&
                                    (*p == '\0' || *p == '/' ||
                                     (p[0] == '\\' && p[1] == '/'))) {
                                        /*
@@ -114,7 +118,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
                                 * only if there are no more slash characters. */
                                if (!match_slash) {
                                        if (strchr((char *)text, '/'))
-                                               return WM_NOMATCH;
+                                               return WM_ABORT_TO_STARSTAR;
                                }
                                return WM_MATCH;
                        } else if (!match_slash && *p == '/') {
@@ -125,7 +129,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
                                 */
                                const char *slash = strchr((char*)text, '/');
                                if (!slash)
-                                       return WM_NOMATCH;
+                                       return WM_ABORT_ALL;
                                text = (const uchar*)slash;
                                /* the slash is consumed by the top-level for loop */
                                break;
@@ -153,8 +157,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
                                                        break;
                                                text++;
                                        }
-                                       if (t_ch != p_ch)
-                                               return WM_NOMATCH;
+                                       if (t_ch != p_ch) {
+                                               if (match_slash)
+                                                       return WM_ABORT_ALL;
+                                               else
+                                                       return WM_ABORT_TO_STARSTAR;
+                                       }
                                }
                                if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
                                        if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
@@ -274,5 +282,6 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
 /* Match the "pattern" against the "text" string. */
 int wildmatch(const char *pattern, const char *text, unsigned int flags)
 {
-       return dowild((const uchar*)pattern, (const uchar*)text, flags);
+       int res = dowild((const uchar*)pattern, (const uchar*)text, flags);
+       return res == WM_MATCH ? WM_MATCH : WM_NOMATCH;
 }
index 599369629824ec5f2bbb8e8affb19e8cc9058cc3..0c890cb56ba303db40a4c4f3244cc4a672303ac1 100644 (file)
@@ -6,8 +6,6 @@
 
 #define WM_NOMATCH 1
 #define WM_MATCH 0
-#define WM_ABORT_ALL -1
-#define WM_ABORT_TO_STARSTAR -2
 
 int wildmatch(const char *pattern, const char *text, unsigned int flags);
 #endif
index aa43c6411914308798a58e4e3a0a5c55d1eede8f..b8cf29e6a1587f5cbb2440a83ef5349fe49d0f48 100644 (file)
@@ -1,6 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "path.h"
 #include "repository.h"
 #include "refs.h"
+#include "setup.h"
 #include "strbuf.h"
 #include "worktree.h"
 #include "dir.h"
@@ -403,44 +408,43 @@ int is_worktree_being_bisected(const struct worktree *wt,
  * bisect). New commands that do similar things should update this
  * function as well.
  */
-const struct worktree *find_shared_symref(struct worktree **worktrees,
-                                         const char *symref,
-                                         const char *target)
+int is_shared_symref(const struct worktree *wt, const char *symref,
+                    const char *target)
 {
-       const struct worktree *existing = NULL;
-       int i = 0;
+       const char *symref_target;
+       struct ref_store *refs;
+       int flags;
 
-       for (i = 0; worktrees[i]; i++) {
-               struct worktree *wt = worktrees[i];
-               const char *symref_target;
-               struct ref_store *refs;
-               int flags;
+       if (wt->is_bare)
+               return 0;
 
-               if (wt->is_bare)
-                       continue;
+       if (wt->is_detached && !strcmp(symref, "HEAD")) {
+               if (is_worktree_being_rebased(wt, target))
+                       return 1;
+               if (is_worktree_being_bisected(wt, target))
+                       return 1;
+       }
 
-               if (wt->is_detached && !strcmp(symref, "HEAD")) {
-                       if (is_worktree_being_rebased(wt, target)) {
-                               existing = wt;
-                               break;
-                       }
-                       if (is_worktree_being_bisected(wt, target)) {
-                               existing = wt;
-                               break;
-                       }
-               }
+       refs = get_worktree_ref_store(wt);
+       symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
+                                               NULL, &flags);
+       if ((flags & REF_ISSYMREF) &&
+           symref_target && !strcmp(symref_target, target))
+               return 1;
 
-               refs = get_worktree_ref_store(wt);
-               symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
-                                                       NULL, &flags);
-               if ((flags & REF_ISSYMREF) &&
-                   symref_target && !strcmp(symref_target, target)) {
-                       existing = wt;
-                       break;
-               }
-       }
+       return 0;
+}
 
-       return existing;
+const struct worktree *find_shared_symref(struct worktree **worktrees,
+                                         const char *symref,
+                                         const char *target)
+{
+
+       for (int i = 0; worktrees[i]; i++)
+               if (is_shared_symref(worktrees[i], symref, target))
+                       return worktrees[i];
+
+       return NULL;
 }
 
 int submodule_uses_worktrees(const char *path)
@@ -801,7 +805,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"));
@@ -830,7 +834,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)))
@@ -841,7 +845,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 9dcea6fc8c1b4fcc387818967d2de99713bfb50b..ce45b66de9e82d4d619b6f74e0e77c8bd5ab3f53 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef WORKTREE_H
 #define WORKTREE_H
 
-#include "cache.h"
 #include "refs.h"
 
 struct strbuf;
@@ -149,6 +148,12 @@ const struct worktree *find_shared_symref(struct worktree **worktrees,
                                          const char *symref,
                                          const char *target);
 
+/*
+ * Returns true if a symref points to a ref in a worktree.
+ */
+int is_shared_symref(const struct worktree *wt,
+                    const char *symref, const char *target);
+
 /*
  * Similar to head_ref() for all HEADs _except_ one from the current
  * worktree, which is covered by head_ref().
index 299d6489a6b0a148b57fa6c8a11f9245e1dfd0dd..5160c9e28de87af79e561db5917d021ad9a3a562 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -1,16 +1,19 @@
 /*
  * Various trivial helper wrappers around standard functions
  */
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
 #include "config.h"
-
-static intmax_t count_fsync_writeout_only;
-static intmax_t count_fsync_hardware_flush;
+#include "gettext.h"
+#include "object.h"
+#include "repository.h"
+#include "strbuf.h"
+#include "trace2.h"
 
 #ifdef HAVE_RTLGENRANDOM
 /* This is required to get access to RtlGenRandom. */
 #define SystemFunction036 NTAPI SystemFunction036
-#include <NTSecAPI.h>
+#include <ntsecapi.h>
 #undef SystemFunction036
 #endif
 
@@ -545,7 +548,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__
                /*
@@ -577,7 +580,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
@@ -594,18 +597,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;
diff --git a/wrapper.h b/wrapper.h
new file mode 100644 (file)
index 0000000..79a9c1b
--- /dev/null
+++ b/wrapper.h
@@ -0,0 +1,142 @@
+#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);
+
+ssize_t read_in_full(int fd, void *buf, size_t count);
+ssize_t write_in_full(int fd, const void *buf, size_t count);
+ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
+
+static inline ssize_t write_str_in_full(int fd, const char *str)
+{
+       return write_in_full(fd, str, strlen(str));
+}
+
+/**
+ * Open (and truncate) the file at path, write the contents of buf to it,
+ * and close it. Dies if any errors are encountered.
+ */
+void write_file_buf(const char *path, const char *buf, size_t len);
+
+/**
+ * Like write_file_buf(), but format the contents into a buffer first.
+ * Additionally, write_file() will append a newline if one is not already
+ * present, making it convenient to write text files:
+ *
+ *   write_file(path, "counter: %d", ctr);
+ */
+__attribute__((format (printf, 2, 3)))
+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);
+/*
+ * 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);
+
+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 /* WRAPPER_H */
index aaa0318e8248116af4d14143eace6c34e59d730b..d8355c0c3e36830f8b9dbd9af696ed3917860c9e 100644 (file)
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "run-command.h"
+#include "write-or-die.h"
 
 /*
  * Some cases use stdio, but want to flush after the write
diff --git a/write-or-die.h b/write-or-die.h
new file mode 100644 (file)
index 0000000..65a5c42
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef WRITE_OR_DIE_H
+#define WRITE_OR_DIE_H
+
+void maybe_flush_or_die(FILE *, const char *);
+__attribute__((format (printf, 2, 3)))
+void fprintf_or_die(FILE *, const char *fmt, ...);
+void fwrite_or_die(FILE *f, const void *buf, size_t count);
+void fflush_or_die(FILE *f);
+void write_or_die(int fd, const void *buf, size_t count);
+
+/*
+ * These values are used to help identify parts of a repository to fsync.
+ * FSYNC_COMPONENT_NONE identifies data that will not be a persistent part of the
+ * repository and so shouldn't be fsynced.
+ */
+enum fsync_component {
+       FSYNC_COMPONENT_NONE,
+       FSYNC_COMPONENT_LOOSE_OBJECT            = 1 << 0,
+       FSYNC_COMPONENT_PACK                    = 1 << 1,
+       FSYNC_COMPONENT_PACK_METADATA           = 1 << 2,
+       FSYNC_COMPONENT_COMMIT_GRAPH            = 1 << 3,
+       FSYNC_COMPONENT_INDEX                   = 1 << 4,
+       FSYNC_COMPONENT_REFERENCE               = 1 << 5,
+};
+
+#define FSYNC_COMPONENTS_OBJECTS (FSYNC_COMPONENT_LOOSE_OBJECT | \
+                                 FSYNC_COMPONENT_PACK)
+
+#define FSYNC_COMPONENTS_DERIVED_METADATA (FSYNC_COMPONENT_PACK_METADATA | \
+                                          FSYNC_COMPONENT_COMMIT_GRAPH)
+
+#define FSYNC_COMPONENTS_DEFAULT ((FSYNC_COMPONENTS_OBJECTS | \
+                                  FSYNC_COMPONENTS_DERIVED_METADATA) & \
+                                 ~FSYNC_COMPONENT_LOOSE_OBJECT)
+
+#define FSYNC_COMPONENTS_COMMITTED (FSYNC_COMPONENTS_OBJECTS | \
+                                   FSYNC_COMPONENT_REFERENCE)
+
+#define FSYNC_COMPONENTS_ADDED (FSYNC_COMPONENTS_COMMITTED | \
+                               FSYNC_COMPONENT_INDEX)
+
+#define FSYNC_COMPONENTS_ALL (FSYNC_COMPONENT_LOOSE_OBJECT | \
+                             FSYNC_COMPONENT_PACK | \
+                             FSYNC_COMPONENT_PACK_METADATA | \
+                             FSYNC_COMPONENT_COMMIT_GRAPH | \
+                             FSYNC_COMPONENT_INDEX | \
+                             FSYNC_COMPONENT_REFERENCE)
+
+#ifndef FSYNC_COMPONENTS_PLATFORM_DEFAULT
+#define FSYNC_COMPONENTS_PLATFORM_DEFAULT FSYNC_COMPONENTS_DEFAULT
+#endif
+
+/* IO helper functions */
+void fsync_or_die(int fd, const char *);
+int fsync_component(enum fsync_component component, int fd);
+void fsync_component_or_die(enum fsync_component component, int fd, const char *msg);
+
+/*
+ * A bitmask indicating which components of the repo should be fsynced.
+ */
+extern enum fsync_component fsync_components;
+extern int fsync_object_files;
+extern int use_fsync;
+
+enum fsync_method {
+       FSYNC_METHOD_FSYNC,
+       FSYNC_METHOD_WRITEOUT_ONLY,
+       FSYNC_METHOD_BATCH,
+};
+
+extern enum fsync_method fsync_method;
+
+static inline int batch_fsync_enabled(enum fsync_component component)
+{
+       return (fsync_components & component) && (fsync_method == FSYNC_METHOD_BATCH);
+}
+
+#endif /* WRITE_OR_DIE_H */
diff --git a/ws.c b/ws.c
index da3d0e28cbba9cb5e5d459f8e807a9a0fcf42102..9456e2fdbe3766b89497cf740b6280770daf5fd8 100644 (file)
--- a/ws.c
+++ b/ws.c
@@ -3,8 +3,12 @@
  *
  * Copyright (c) 2007 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "attr.h"
+#include "strbuf.h"
+#include "ws.h"
+
+unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
 
 static struct whitespace_rule {
        const char *rule_name;
@@ -79,7 +83,7 @@ unsigned whitespace_rule(struct index_state *istate, const char *pathname)
        if (!attr_whitespace_rule)
                attr_whitespace_rule = attr_check_initl("whitespace", NULL);
 
-       git_check_attr(istate, NULL, pathname, attr_whitespace_rule);
+       git_check_attr(istate, pathname, attr_whitespace_rule);
        value = attr_whitespace_rule->items[0].value;
        if (ATTR_TRUE(value)) {
                /* true (whitespace) */
diff --git a/ws.h b/ws.h
new file mode 100644 (file)
index 0000000..5ba676c
--- /dev/null
+++ b/ws.h
@@ -0,0 +1,33 @@
+#ifndef WS_H
+#define WS_H
+
+struct index_state;
+struct strbuf;
+
+/*
+ * whitespace rules.
+ * used by both diff and apply
+ * last two digits are tab width
+ */
+#define WS_BLANK_AT_EOL         0100
+#define WS_SPACE_BEFORE_TAB     0200
+#define WS_INDENT_WITH_NON_TAB  0400
+#define WS_CR_AT_EOL           01000
+#define WS_BLANK_AT_EOF        02000
+#define WS_TAB_IN_INDENT       04000
+#define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
+#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
+#define WS_TAB_WIDTH_MASK        077
+/* All WS_* -- when extended, adapt diff.c emit_symbol */
+#define WS_RULE_MASK           07777
+extern unsigned whitespace_rule_cfg;
+unsigned whitespace_rule(struct index_state *, const char *);
+unsigned parse_whitespace_rule(const char *);
+unsigned ws_check(const char *line, int len, unsigned ws_rule);
+void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
+char *whitespace_error_string(unsigned ws);
+void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
+int ws_blank_line(const char *line, int len);
+#define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
+
+#endif /* WS_H */
index 3162241a570cb60393607f06a8a12963b71afb78..d03dfab9e47d128b15295e499c8113346a593cf7 100644 (file)
@@ -1,9 +1,16 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "advice.h"
 #include "wt-status.h"
 #include "object.h"
 #include "dir.h"
 #include "commit.h"
 #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"
 #include "refs.h"
 #include "submodule.h"
 #include "column.h"
+#include "read-cache.h"
+#include "setup.h"
 #include "strbuf.h"
+#include "trace.h"
+#include "trace2.h"
+#include "tree.h"
 #include "utf8.h"
 #include "worktree.h"
 #include "lockfile.h"
@@ -663,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);
 }
 
@@ -1015,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);
        }
 
@@ -1090,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)
@@ -1144,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,
@@ -1174,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) &&
@@ -1337,7 +1350,7 @@ static void abbrev_oid_in_line(struct strbuf *line)
                 * it after abbreviation.
                 */
                strbuf_trim(split[1]);
-               if (!get_oid(split[1]->buf, &oid)) {
+               if (!repo_get_oid(the_repository, split[1]->buf, &oid)) {
                        strbuf_reset(split[1]);
                        strbuf_add_unique_abbrev(split[1], &oid,
                                                 DEFAULT_ABBREV);
@@ -1503,8 +1516,8 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
        else
                status_printf_ln(s, color,
                        _("You are currently cherry-picking commit %s."),
-                       find_unique_abbrev(&s->state.cherry_pick_head_oid,
-                                          DEFAULT_ABBREV));
+                       repo_find_unique_abbrev(the_repository, &s->state.cherry_pick_head_oid,
+                                               DEFAULT_ABBREV));
 
        if (s->hints) {
                if (has_unmerged(s))
@@ -1533,8 +1546,8 @@ static void show_revert_in_progress(struct wt_status *s,
        else
                status_printf_ln(s, color,
                        _("You are currently reverting commit %s."),
-                       find_unique_abbrev(&s->state.revert_head_oid,
-                                          DEFAULT_ABBREV));
+                       repo_find_unique_abbrev(the_repository, &s->state.revert_head_oid,
+                                               DEFAULT_ABBREV));
        if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
@@ -1664,7 +1677,8 @@ static void wt_status_get_detached_from(struct repository *r,
                return;
        }
 
-       if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref, 1) == 1 &&
+       if (repo_dwim_ref(r, cb.buf.buf, cb.buf.len, &oid, &ref,
+                         1) == 1 &&
            /* oid is a commit? match without further lookup */
            (oideq(&cb.noid, &oid) ||
             /* perhaps oid is a tag, try to dereference to a commit */
@@ -1676,9 +1690,9 @@ static void wt_status_get_detached_from(struct repository *r,
                state->detached_from = xstrdup(from);
        } else
                state->detached_from =
-                       xstrdup(find_unique_abbrev(&cb.noid, DEFAULT_ABBREV));
+                       xstrdup(repo_find_unique_abbrev(r, &cb.noid, DEFAULT_ABBREV));
        oidcpy(&state->detached_oid, &cb.noid);
-       state->detached_at = !get_oid("HEAD", &oid) &&
+       state->detached_at = !repo_get_oid(r, "HEAD", &oid) &&
                             oideq(&oid, &state->detached_oid);
 
        free(ref);
@@ -1769,21 +1783,21 @@ void wt_status_get_state(struct repository *r,
        } else if (wt_status_check_rebase(NULL, state)) {
                ;               /* all set */
        } else if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
-                  !get_oid("CHERRY_PICK_HEAD", &oid)) {
+                  !repo_get_oid(r, "CHERRY_PICK_HEAD", &oid)) {
                state->cherry_pick_in_progress = 1;
                oidcpy(&state->cherry_pick_head_oid, &oid);
        }
        wt_status_check_bisect(NULL, state);
        if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") &&
-           !get_oid("REVERT_HEAD", &oid)) {
+           !repo_get_oid(r, "REVERT_HEAD", &oid)) {
                state->revert_in_progress = 1;
                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());
                }
@@ -2566,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;
 }
@@ -2600,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;
 }
@@ -2641,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 e87950de32e5602765de26953ce7ec812ef30925..adcea109fa9a54eaa96c67c1b5e8a1689af253af 100644 (file)
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "strbuf.h"
 #include "xdiff-interface.h"
 #include "xdiff/xtypes.h"
 #include "xdiff/xdiffi.h"
@@ -183,7 +185,7 @@ void read_mmblob(mmfile_t *ptr, const struct object_id *oid)
                return;
        }
 
-       ptr->ptr = read_object_file(oid, &type, &size);
+       ptr->ptr = repo_read_object_file(the_repository, oid, &type, &size);
        if (!ptr->ptr || type != OBJ_BLOB)
                die("unable to read blob object %s", oid_to_hex(oid));
        ptr->size = size;
@@ -306,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)
@@ -326,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 4301a7eef274bb7796ad758d686f61b7c5b35395..e6f80df04627ccfe1b3777fe380ef3aa5188769e 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef XDIFF_INTERFACE_H
 #define XDIFF_INTERFACE_H
 
-#include "cache.h"
+#include "hash-ll.h"
 #include "xdiff/xdiff.h"
 
 /*
@@ -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;
 
 /*